diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 2f4f1c8a..a438009f 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -511,12 +511,50 @@ export default class CodeEditor extends React.Component { handleChange (editor, changeObject) { spellcheck.handleChange(editor, changeObject) + + this.updateHighlight(editor, changeObject) + this.value = editor.getValue() if (this.props.onChange) { this.props.onChange(editor) } } + incrementLines (start, linesAdded, linesRemoved, editor) { + let highlightedLines = editor.options.linesHighlighted + + const totalHighlightedLines = highlightedLines.length + + let offset = linesAdded - linesRemoved + + // Store new items to be added as we're changing the lines + let newLines = [] + + let i = totalHighlightedLines + + while (i--) { + const lineNumber = highlightedLines[i] + + // Interval that will need to be updated + // Between start and (start + offset) remove highlight + if (lineNumber >= start) { + highlightedLines.splice(highlightedLines.indexOf(lineNumber), 1) + + // Lines that need to be relocated + if (lineNumber >= (start + linesRemoved)) { + newLines.push(lineNumber + offset) + } + } + } + + // Adding relocated lines + highlightedLines.push(...newLines) + + if (this.props.onChange) { + this.props.onChange(editor) + } + } + handleHighlight (editor, changeObject) { const lines = editor.options.linesHighlighted @@ -532,6 +570,37 @@ export default class CodeEditor extends React.Component { } } + updateHighlight (editor, changeObject) { + const linesAdded = changeObject.text.length - 1 + const linesRemoved = changeObject.removed.length - 1 + + // If no lines added or removed return + if (linesAdded === 0 && linesRemoved === 0) { + return + } + + let start = changeObject.from.line + + switch (changeObject.origin) { + case '+insert", "undo': + start += 1 + break + + case 'paste': + case '+delete': + case '+input': + if (changeObject.to.ch !== 0 || changeObject.from.ch !== 0) { + start += 1 + } + break + + default: + return + } + + this.incrementLines(start, linesAdded, linesRemoved, editor) + } + moveCursorTo (row, col) {} scrollToLine (event, num) { diff --git a/tests/dataApi/createNote-test.js b/tests/dataApi/createNote-test.js index 47446aab..3606dfd4 100644 --- a/tests/dataApi/createNote-test.js +++ b/tests/dataApi/createNote-test.js @@ -25,13 +25,16 @@ test.serial('Create a note', (t) => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key + const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10)) + const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), snippets: [{ name: faker.system.fileName(), mode: 'text', - content: faker.lorem.lines() + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray }], tags: faker.lorem.words().split(' '), folder: folderKey @@ -42,7 +45,8 @@ test.serial('Create a note', (t) => { type: 'MARKDOWN_NOTE', content: faker.lorem.lines(), tags: faker.lorem.words().split(' '), - folder: folderKey + folder: folderKey, + linesHighlighted: randLinesHighlightedArray } input2.title = input2.content.split('\n').shift() @@ -59,6 +63,7 @@ test.serial('Create a note', (t) => { t.is(storageKey, data1.storage) const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson')) + t.is(input1.title, data1.title) t.is(input1.title, jsonData1.title) t.is(input1.description, data1.description) @@ -71,6 +76,8 @@ test.serial('Create a note', (t) => { t.is(input1.snippets[0].content, jsonData1.snippets[0].content) t.is(input1.snippets[0].name, data1.snippets[0].name) t.is(input1.snippets[0].name, jsonData1.snippets[0].name) + t.deepEqual(input1.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted) + t.deepEqual(input1.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted) t.is(storageKey, data2.storage) const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson')) @@ -80,6 +87,8 @@ test.serial('Create a note', (t) => { t.is(input2.content, jsonData2.content) t.is(input2.tags.length, data2.tags.length) t.is(input2.tags.length, jsonData2.tags.length) + t.deepEqual(input2.linesHighlighted, data2.linesHighlighted) + t.deepEqual(input2.linesHighlighted, jsonData2.linesHighlighted) }) }) diff --git a/tests/dataApi/createSnippet-test.js b/tests/dataApi/createSnippet-test.js index f06cf861..638b76ca 100644 --- a/tests/dataApi/createSnippet-test.js +++ b/tests/dataApi/createSnippet-test.js @@ -26,6 +26,7 @@ test.serial('Create a snippet', (t) => { t.is(snippet.name, data.name) t.deepEqual(snippet.prefix, data.prefix) t.is(snippet.content, data.content) + t.deepEqual(snippet.linesHighlighted, data.linesHighlighted) }) }) diff --git a/tests/dataApi/updateNote-test.js b/tests/dataApi/updateNote-test.js index 6043ee1e..da47c30c 100644 --- a/tests/dataApi/updateNote-test.js +++ b/tests/dataApi/updateNote-test.js @@ -26,13 +26,17 @@ test.serial('Update a note', (t) => { const storageKey = t.context.storage.cache.key const folderKey = t.context.storage.json.folders[0].key + const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10)) + const randLinesHighlightedArray2 = new Array(15).fill().map(() => Math.round(Math.random() * 15)) + const input1 = { type: 'SNIPPET_NOTE', description: faker.lorem.lines(), snippets: [{ name: faker.system.fileName(), mode: 'text', - content: faker.lorem.lines() + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray }], tags: faker.lorem.words().split(' '), folder: folderKey @@ -43,7 +47,8 @@ test.serial('Update a note', (t) => { type: 'MARKDOWN_NOTE', content: faker.lorem.lines(), tags: faker.lorem.words().split(' '), - folder: folderKey + folder: folderKey, + linesHighlighted: randLinesHighlightedArray } input2.title = input2.content.split('\n').shift() @@ -53,7 +58,8 @@ test.serial('Update a note', (t) => { snippets: [{ name: faker.system.fileName(), mode: 'text', - content: faker.lorem.lines() + content: faker.lorem.lines(), + linesHighlighted: randLinesHighlightedArray2 }], tags: faker.lorem.words().split(' ') } @@ -62,7 +68,8 @@ test.serial('Update a note', (t) => { const input4 = { type: 'MARKDOWN_NOTE', content: faker.lorem.lines(), - tags: faker.lorem.words().split(' ') + tags: faker.lorem.words().split(' '), + linesHighlighted: randLinesHighlightedArray2 } input4.title = input4.content.split('\n').shift() @@ -99,6 +106,8 @@ test.serial('Update a note', (t) => { t.is(input3.snippets[0].content, jsonData1.snippets[0].content) t.is(input3.snippets[0].name, data1.snippets[0].name) t.is(input3.snippets[0].name, jsonData1.snippets[0].name) + t.deepEqual(input3.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted) + t.deepEqual(input3.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted) const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson')) t.is(input4.title, data2.title) @@ -107,6 +116,8 @@ test.serial('Update a note', (t) => { t.is(input4.content, jsonData2.content) t.is(input4.tags.length, data2.tags.length) t.is(input4.tags.length, jsonData2.tags.length) + t.deepEqual(input4.linesHighlighted, data2.linesHighlighted) + t.deepEqual(input4.linesHighlighted, jsonData2.linesHighlighted) }) })