mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
Corrections to make line highlighting robust, added tests
Lines now save correctly with different inputs, making sure that different inputs like enter, delete, paste and where it's deleted stay consistent when saving. Included in the create/update snippet/note tests the structure from lines highlighting saved to the files.
This commit is contained in:
@@ -511,12 +511,50 @@ export default class CodeEditor extends React.Component {
|
|||||||
|
|
||||||
handleChange (editor, changeObject) {
|
handleChange (editor, changeObject) {
|
||||||
spellcheck.handleChange(editor, changeObject)
|
spellcheck.handleChange(editor, changeObject)
|
||||||
|
|
||||||
|
this.updateHighlight(editor, changeObject)
|
||||||
|
|
||||||
this.value = editor.getValue()
|
this.value = editor.getValue()
|
||||||
if (this.props.onChange) {
|
if (this.props.onChange) {
|
||||||
this.props.onChange(editor)
|
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) {
|
handleHighlight (editor, changeObject) {
|
||||||
const lines = editor.options.linesHighlighted
|
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) {}
|
moveCursorTo (row, col) {}
|
||||||
|
|
||||||
scrollToLine (event, num) {
|
scrollToLine (event, num) {
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ test.serial('Create a note', (t) => {
|
|||||||
const storageKey = t.context.storage.cache.key
|
const storageKey = t.context.storage.cache.key
|
||||||
const folderKey = t.context.storage.json.folders[0].key
|
const folderKey = t.context.storage.json.folders[0].key
|
||||||
|
|
||||||
|
const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
|
||||||
|
|
||||||
const input1 = {
|
const input1 = {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
description: faker.lorem.lines(),
|
description: faker.lorem.lines(),
|
||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey
|
||||||
@@ -42,7 +45,8 @@ test.serial('Create a note', (t) => {
|
|||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey,
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}
|
}
|
||||||
input2.title = input2.content.split('\n').shift()
|
input2.title = input2.content.split('\n').shift()
|
||||||
|
|
||||||
@@ -59,6 +63,7 @@ test.serial('Create a note', (t) => {
|
|||||||
|
|
||||||
t.is(storageKey, data1.storage)
|
t.is(storageKey, data1.storage)
|
||||||
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
|
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
|
||||||
|
|
||||||
t.is(input1.title, data1.title)
|
t.is(input1.title, data1.title)
|
||||||
t.is(input1.title, jsonData1.title)
|
t.is(input1.title, jsonData1.title)
|
||||||
t.is(input1.description, data1.description)
|
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].content, jsonData1.snippets[0].content)
|
||||||
t.is(input1.snippets[0].name, data1.snippets[0].name)
|
t.is(input1.snippets[0].name, data1.snippets[0].name)
|
||||||
t.is(input1.snippets[0].name, jsonData1.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)
|
t.is(storageKey, data2.storage)
|
||||||
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
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.content, jsonData2.content)
|
||||||
t.is(input2.tags.length, data2.tags.length)
|
t.is(input2.tags.length, data2.tags.length)
|
||||||
t.is(input2.tags.length, jsonData2.tags.length)
|
t.is(input2.tags.length, jsonData2.tags.length)
|
||||||
|
t.deepEqual(input2.linesHighlighted, data2.linesHighlighted)
|
||||||
|
t.deepEqual(input2.linesHighlighted, jsonData2.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ test.serial('Create a snippet', (t) => {
|
|||||||
t.is(snippet.name, data.name)
|
t.is(snippet.name, data.name)
|
||||||
t.deepEqual(snippet.prefix, data.prefix)
|
t.deepEqual(snippet.prefix, data.prefix)
|
||||||
t.is(snippet.content, data.content)
|
t.is(snippet.content, data.content)
|
||||||
|
t.deepEqual(snippet.linesHighlighted, data.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,17 @@ test.serial('Update a note', (t) => {
|
|||||||
const storageKey = t.context.storage.cache.key
|
const storageKey = t.context.storage.cache.key
|
||||||
const folderKey = t.context.storage.json.folders[0].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 = {
|
const input1 = {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
description: faker.lorem.lines(),
|
description: faker.lorem.lines(),
|
||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey
|
||||||
@@ -43,7 +47,8 @@ test.serial('Update a note', (t) => {
|
|||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey,
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}
|
}
|
||||||
input2.title = input2.content.split('\n').shift()
|
input2.title = input2.content.split('\n').shift()
|
||||||
|
|
||||||
@@ -53,7 +58,8 @@ test.serial('Update a note', (t) => {
|
|||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray2
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' ')
|
tags: faker.lorem.words().split(' ')
|
||||||
}
|
}
|
||||||
@@ -62,7 +68,8 @@ test.serial('Update a note', (t) => {
|
|||||||
const input4 = {
|
const input4 = {
|
||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' ')
|
tags: faker.lorem.words().split(' '),
|
||||||
|
linesHighlighted: randLinesHighlightedArray2
|
||||||
}
|
}
|
||||||
input4.title = input4.content.split('\n').shift()
|
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].content, jsonData1.snippets[0].content)
|
||||||
t.is(input3.snippets[0].name, data1.snippets[0].name)
|
t.is(input3.snippets[0].name, data1.snippets[0].name)
|
||||||
t.is(input3.snippets[0].name, jsonData1.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'))
|
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
||||||
t.is(input4.title, data2.title)
|
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.content, jsonData2.content)
|
||||||
t.is(input4.tags.length, data2.tags.length)
|
t.is(input4.tags.length, data2.tags.length)
|
||||||
t.is(input4.tags.length, jsonData2.tags.length)
|
t.is(input4.tags.length, jsonData2.tags.length)
|
||||||
|
t.deepEqual(input4.linesHighlighted, data2.linesHighlighted)
|
||||||
|
t.deepEqual(input4.linesHighlighted, jsonData2.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user