Skip to content

Commit

Permalink
feat! switch from decoration ids to decoration filter
Browse files Browse the repository at this point in the history
and make tools more robust
  • Loading branch information
Loïc Mangeonjean committed Feb 5, 2024
1 parent 8f4e492 commit 21e6060
Showing 1 changed file with 54 additions and 16 deletions.
70 changes: 54 additions & 16 deletions src/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ function isPasteAction (handlerId: string, payload: unknown): payload is PastePa
}

export function lockCodeWithoutDecoration (
editor: monaco.editor.IStandaloneCodeEditor,
decorations: string[],
editor: monaco.editor.ICodeEditor,
decorationFilter: (decoration: monaco.editor.IModelDecoration) => boolean,
allowChangeFromSources: string[] = [],
errorMessage?: string
): monaco.IDisposable {
Expand All @@ -30,8 +30,14 @@ export function lockCodeWithoutDecoration (
function canEditRange (range: monaco.IRange) {
const model = editor.getModel()
if (model != null) {
const editableRanges = decorations.map(decoration => model.getDecorationRange(decoration))
return editableRanges.some(editableRange => editableRange?.containsRange(range) ?? false)
const editableRanges = model
.getAllDecorations()
.filter(decorationFilter)
.map((decoration) => decoration.range)
if (editableRanges.length === 0) {
return true
}
return editableRanges.some((editableRange) => editableRange.containsRange(range))
}
return false
}
Expand All @@ -52,7 +58,13 @@ export function lockCodeWithoutDecoration (
const originalTrigger = editor.trigger
editor.trigger = function (source, handlerId, payload) {
// Try to transform whole file pasting into a paste in the editable area only
const lastEditableRange = decorations.length > 0 ? editor.getModel()?.getDecorationRange(decorations[decorations.length - 1]!) : null
const editableRanges = editor
.getModel()!
.getAllDecorations()
.filter(decorationFilter)
.map((decoration) => decoration.range)
const lastEditableRange =
editableRanges.length > 0 ? editableRanges[editableRanges.length - 1] : undefined
if (isPasteAction(handlerId, payload) && lastEditableRange != null) {
const selections = editor.getSelections()
const model = editor.getModel()!
Expand All @@ -63,10 +75,12 @@ export function lockCodeWithoutDecoration (
if (wholeFileSelected) {
const currentEditorValue = editor.getValue()
const before = model.getOffsetAt(lastEditableRange.getStartPosition())
const after = currentEditorValue.length - model.getOffsetAt(lastEditableRange.getEndPosition())
const after =
currentEditorValue.length - model.getOffsetAt(lastEditableRange.getEndPosition())
if (
currentEditorValue.slice(0, before) === payload.text.slice(0, before) &&
currentEditorValue.slice(currentEditorValue.length - after) === payload.text.slice(payload.text.length - after)
currentEditorValue.slice(currentEditorValue.length - after) ===
payload.text.slice(payload.text.length - after)
) {
editor.setSelection(lastEditableRange)
const newPayload: PastePayload = {
Expand All @@ -81,7 +95,7 @@ export function lockCodeWithoutDecoration (

if (['type', 'paste', 'cut'].includes(handlerId)) {
const selections = editor.getSelections()
if (selections != null && selections.some(range => !canEditRange(range))) {
if (selections != null && selections.some((range) => !canEditRange(range))) {
displayLockedCodeError(editor.getPosition()!)
return
}
Expand All @@ -107,16 +121,23 @@ export function lockCodeWithoutDecoration (
if (model == null) {
return
}
const originalApplyEdit: (operations: monaco.editor.IIdentifiedSingleEditOperation[], computeUndoEdits?: boolean) => void = model.applyEdits
model.applyEdits = ((operations: monaco.editor.IIdentifiedSingleEditOperation[], computeUndoEdits?: boolean) => {
const originalApplyEdit: (
operations: monaco.editor.IIdentifiedSingleEditOperation[],
computeUndoEdits?: boolean
) => void = model.applyEdits
model.applyEdits = ((
operations: monaco.editor.IIdentifiedSingleEditOperation[],
computeUndoEdits?: boolean
) => {
if (currentEditSource != null && allowChangeFromSources.includes(currentEditSource)) {
return originalApplyEdit.call(model, operations, computeUndoEdits!)
}
const filteredOperations = operations
.filter(operation => canEditRange(operation.range))
const filteredOperations = operations.filter((operation) => canEditRange(operation.range))
if (filteredOperations.length === 0 && operations.length > 0) {
const firstRange = operations[0]!.range
displayLockedCodeError(new monaco.Position(firstRange.startLineNumber, firstRange.startColumn))
displayLockedCodeError(
new monaco.Position(firstRange.startLineNumber, firstRange.startColumn)
)
}
return originalApplyEdit.call(model, filteredOperations, computeUndoEdits!)
}) as typeof model.applyEdits
Expand Down Expand Up @@ -160,13 +181,22 @@ export function lockCodeWithoutDecoration (
return disposableStore
}

export function hideCodeWithoutDecoration (editor: monaco.editor.IStandaloneCodeEditor, decorations: string[]): monaco.IDisposable {
export function hideCodeWithoutDecoration (editor: monaco.editor.ICodeEditor, decorationFilter: (decoration: monaco.editor.IModelDecoration) => boolean): monaco.IDisposable {
let otherHiddenAreas: monaco.IRange[] = editor._getViewModel()?.getHiddenAreas() ?? []
function getHiddenAreas () {
const model = editor.getModel()!
const model = editor.getModel()
if (model == null) {
return []
}

const decorations = model.getAllDecorations()
.filter(decorationFilter)
if (decorations.length === 0) {
return otherHiddenAreas
}

const ranges = decorations
.map(decoration => model.getDecorationRange(decoration)!)
.map(decoration => decoration.range)
.sort((a, b) => a.startLineNumber - b.startLineNumber)
// merge ranges
.reduce<monaco.Range[]>((acc, range) => {
Expand Down Expand Up @@ -218,6 +248,14 @@ export function hideCodeWithoutDecoration (editor: monaco.editor.IStandaloneCode
}

const disposableStore = new DisposableStore()

disposableStore.add(editor.onDidChangeModel(() => {
otherHiddenAreas = editor._getViewModel()?.getHiddenAreas() ?? []
updateHiddenAreas()
}))
disposableStore.add(editor.onDidChangeModelDecorations(() => {
updateHiddenAreas()
}))
updateHiddenAreas()

disposableStore.add({
Expand Down

0 comments on commit 21e6060

Please sign in to comment.