mirror of
https://github.com/heyman/heynote.git
synced 2024-12-27 17:18:53 +01:00
Add commands for selecting next/previous block/paragraph
This commit is contained in:
parent
ed13baf4e4
commit
a5d47d81f6
@ -94,114 +94,141 @@ export function changeCurrentBlockLanguage(state, dispatch, language, auto) {
|
||||
changeLanguageTo(state, dispatch, block, language, auto)
|
||||
}
|
||||
|
||||
export function gotoPreviousBlock({state, dispatch}) {
|
||||
function updateSel(sel, by) {
|
||||
return EditorSelection.create(sel.ranges.map(by), sel.mainIndex);
|
||||
}
|
||||
function setSel(state, selection) {
|
||||
return state.update({ selection, scrollIntoView: true, userEvent: "select" });
|
||||
}
|
||||
function extendSel(state, dispatch, how) {
|
||||
let selection = updateSel(state.selection, range => {
|
||||
let head = how(range);
|
||||
return EditorSelection.range(range.anchor, head.head, head.goalColumn, head.bidiLevel || undefined);
|
||||
});
|
||||
if (selection.eq(state.selection))
|
||||
return false;
|
||||
dispatch(setSel(state, selection));
|
||||
return true;
|
||||
}
|
||||
function moveSel(state, dispatch, how) {
|
||||
let selection = updateSel(state.selection, how);
|
||||
if (selection.eq(state.selection))
|
||||
return false;
|
||||
dispatch(setSel(state, selection));
|
||||
return true;
|
||||
}
|
||||
|
||||
function previousBlock(state, range) {
|
||||
const blocks = state.facet(blockState)
|
||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
||||
const block = getNoteBlockFromPos(state, sel.head)
|
||||
if (sel.head === block.content.from) {
|
||||
const index = blocks.indexOf(block)
|
||||
const previousBlockIndex = index > 0 ? index - 1 : 0
|
||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.from)
|
||||
} else {
|
||||
return EditorSelection.cursor(block.content.from)
|
||||
}
|
||||
}), state.selection.mainIndex)
|
||||
dispatch(state.update({
|
||||
selection: newSelection,
|
||||
scrollIntoView: true,
|
||||
}))
|
||||
return true
|
||||
const block = getNoteBlockFromPos(state, range.head)
|
||||
if (range.head === block.content.from) {
|
||||
const index = blocks.indexOf(block)
|
||||
const previousBlockIndex = index > 0 ? index - 1 : 0
|
||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.from)
|
||||
} else {
|
||||
return EditorSelection.cursor(block.content.from)
|
||||
}
|
||||
}
|
||||
|
||||
function nextBlock(state, range) {
|
||||
const blocks = state.facet(blockState)
|
||||
const block = getNoteBlockFromPos(state, range.head)
|
||||
if (range.head === block.content.to) {
|
||||
const index = blocks.indexOf(block)
|
||||
const previousBlockIndex = index < blocks.length - 1 ? index + 1 : index
|
||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.to)
|
||||
} else {
|
||||
return EditorSelection.cursor(block.content.to)
|
||||
}
|
||||
}
|
||||
|
||||
export function gotoNextBlock({state, dispatch}) {
|
||||
const blocks = state.facet(blockState)
|
||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
||||
const block = getNoteBlockFromPos(state, sel.head)
|
||||
if (sel.head === block.content.to) {
|
||||
const index = blocks.indexOf(block)
|
||||
const previousBlockIndex = index < blocks.length - 1 ? index + 1 : index
|
||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.to)
|
||||
} else {
|
||||
return EditorSelection.cursor(block.content.to)
|
||||
}
|
||||
}), state.selection.mainIndex)
|
||||
dispatch(state.update({
|
||||
selection: newSelection,
|
||||
scrollIntoView: true,
|
||||
}))
|
||||
return true
|
||||
return moveSel(state, dispatch, range => nextBlock(state, range))
|
||||
}
|
||||
export function selectNextBlock({state, dispatch}) {
|
||||
return extendSel(state, dispatch, range => nextBlock(state, range))
|
||||
}
|
||||
export function gotoPreviousBlock({state, dispatch}) {
|
||||
return moveSel(state, dispatch, range => previousBlock(state, range))
|
||||
}
|
||||
export function selectPreviousBlock({state, dispatch}) {
|
||||
return extendSel(state, dispatch, range => previousBlock(state, range))
|
||||
}
|
||||
|
||||
export function gotoPreviousParagraph({state, dispatch}) {
|
||||
|
||||
function previousParagraph(state, range) {
|
||||
const blocks = state.facet(blockState)
|
||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
||||
let block = getNoteBlockFromPos(state, sel.head)
|
||||
const blockIndex = blocks.indexOf(block)
|
||||
let block = getNoteBlockFromPos(state, range.head)
|
||||
const blockIndex = blocks.indexOf(block)
|
||||
|
||||
let seenContentLine = false
|
||||
let pos
|
||||
// if we're on the first row of a block, and it's not the first block, we start from the end of the previous block
|
||||
if (state.doc.lineAt(sel.head).from === block.content.from && blockIndex > 0) {
|
||||
block = blocks[blockIndex - 1]
|
||||
pos = state.doc.lineAt(block.content.to).from
|
||||
} else {
|
||||
pos = state.doc.lineAt(sel.head).from
|
||||
}
|
||||
let seenContentLine = false
|
||||
let pos
|
||||
// if we're on the first row of a block, and it's not the first block, we start from the end of the previous block
|
||||
if (state.doc.lineAt(range.head).from === block.content.from && blockIndex > 0) {
|
||||
block = blocks[blockIndex - 1]
|
||||
pos = state.doc.lineAt(block.content.to).from
|
||||
} else {
|
||||
pos = state.doc.lineAt(range.head).from
|
||||
}
|
||||
|
||||
while (pos > block.content.from) {
|
||||
const line = state.doc.lineAt(pos)
|
||||
if (line.text.replace(/\s/g, '').length == 0) {
|
||||
if (seenContentLine) {
|
||||
return EditorSelection.cursor(line.from)
|
||||
}
|
||||
} else {
|
||||
seenContentLine = true
|
||||
while (pos > block.content.from) {
|
||||
const line = state.doc.lineAt(pos)
|
||||
if (line.text.replace(/\s/g, '').length == 0) {
|
||||
if (seenContentLine) {
|
||||
return EditorSelection.cursor(line.from)
|
||||
}
|
||||
// set position to beginning go previous line
|
||||
pos = state.doc.lineAt(line.from - 1).from
|
||||
} else {
|
||||
seenContentLine = true
|
||||
}
|
||||
return EditorSelection.cursor(block.content.from)
|
||||
}), state.selection.mainIndex)
|
||||
dispatch(state.update({
|
||||
selection: newSelection,
|
||||
scrollIntoView: true,
|
||||
}))
|
||||
return true
|
||||
// set position to beginning go previous line
|
||||
pos = state.doc.lineAt(line.from - 1).from
|
||||
}
|
||||
return EditorSelection.cursor(block.content.from)
|
||||
}
|
||||
|
||||
|
||||
function nextParagraph(state, range) {
|
||||
const blocks = state.facet(blockState)
|
||||
let block = getNoteBlockFromPos(state, range.head)
|
||||
const blockIndex = blocks.indexOf(block)
|
||||
|
||||
let seenContentLine = false
|
||||
let pos
|
||||
// if we're at the last line of a block, and it's not the last block, we start from the beginning of the next block
|
||||
if (state.doc.lineAt(range.head).to === block.content.to && blockIndex < blocks.length - 1) {
|
||||
block = blocks[blockIndex + 1]
|
||||
pos = state.doc.lineAt(block.content.from).to
|
||||
} else {
|
||||
pos = state.doc.lineAt(range.head).to
|
||||
}
|
||||
|
||||
while (pos < block.content.to) {
|
||||
const line = state.doc.lineAt(pos)
|
||||
if (line.text.replace(/\s/g, '').length == 0) {
|
||||
if (seenContentLine) {
|
||||
return EditorSelection.cursor(line.from)
|
||||
}
|
||||
} else {
|
||||
seenContentLine = true
|
||||
}
|
||||
// set position to beginning go previous line
|
||||
pos = state.doc.lineAt(line.to + 1).to
|
||||
}
|
||||
return EditorSelection.cursor(block.content.to)
|
||||
}
|
||||
|
||||
export function gotoNextParagraph({state, dispatch}) {
|
||||
const blocks = state.facet(blockState)
|
||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
||||
let block = getNoteBlockFromPos(state, sel.head)
|
||||
const blockIndex = blocks.indexOf(block)
|
||||
|
||||
let seenContentLine = false
|
||||
let pos
|
||||
// if we're at the last line of a block, and it's not the last block, we start from the beginning of the next block
|
||||
if (state.doc.lineAt(sel.head).to === block.content.to && blockIndex < blocks.length - 1) {
|
||||
block = blocks[blockIndex + 1]
|
||||
pos = state.doc.lineAt(block.content.from).to
|
||||
} else {
|
||||
pos = state.doc.lineAt(sel.head).to
|
||||
}
|
||||
|
||||
while (pos < block.content.to) {
|
||||
const line = state.doc.lineAt(pos)
|
||||
if (line.text.replace(/\s/g, '').length == 0) {
|
||||
if (seenContentLine) {
|
||||
return EditorSelection.cursor(line.from)
|
||||
}
|
||||
} else {
|
||||
seenContentLine = true
|
||||
}
|
||||
// set position to beginning go previous line
|
||||
pos = state.doc.lineAt(line.to + 1).to
|
||||
}
|
||||
return EditorSelection.cursor(block.content.to)
|
||||
}), state.selection.mainIndex)
|
||||
dispatch(state.update({
|
||||
selection: newSelection,
|
||||
scrollIntoView: true,
|
||||
}))
|
||||
return true
|
||||
return moveSel(state, dispatch, range => nextParagraph(state, range))
|
||||
}
|
||||
|
||||
export function selectNextParagraph({state, dispatch}) {
|
||||
return extendSel(state, dispatch, range => nextParagraph(state, range))
|
||||
}
|
||||
|
||||
export function gotoPreviousParagraph({state, dispatch}) {
|
||||
return moveSel(state, dispatch, range => previousParagraph(state, range))
|
||||
}
|
||||
|
||||
export function selectPreviousParagraph({state, dispatch}) {
|
||||
return extendSel(state, dispatch, range => previousParagraph(state, range))
|
||||
}
|
@ -1,7 +1,16 @@
|
||||
import { EditorView, keymap } from "@codemirror/view"
|
||||
import { EditorSelection } from "@codemirror/state"
|
||||
import { indentWithTab, insertTab, indentLess, indentMore, undo, redo } from "@codemirror/commands"
|
||||
import { insertNewBlockAtCursor, addNewBlockAfterCurrent, moveLineUp, moveLineDown, selectAll, gotoPreviousBlock, gotoNextBlock, gotoPreviousParagraph, gotoNextParagraph } from "./block/commands.js";
|
||||
import {
|
||||
insertNewBlockAtCursor,
|
||||
addNewBlockAfterCurrent,
|
||||
moveLineUp, moveLineDown,
|
||||
selectAll,
|
||||
gotoPreviousBlock, gotoNextBlock,
|
||||
selectNextBlock, selectPreviousBlock,
|
||||
gotoPreviousParagraph, gotoNextParagraph,
|
||||
selectNextParagraph, selectPreviousParagraph,
|
||||
} from "./block/commands.js";
|
||||
|
||||
export function heynoteKeymap(editor) {
|
||||
return keymap.of([
|
||||
@ -14,8 +23,12 @@ export function heynoteKeymap(editor) {
|
||||
["Alt-ArrowDown", moveLineDown],
|
||||
["Mod-ArrowUp", gotoPreviousBlock],
|
||||
["Mod-ArrowDown", gotoNextBlock],
|
||||
["Mod-Shift-ArrowUp", selectPreviousBlock],
|
||||
["Mod-Shift-ArrowDown", selectNextBlock],
|
||||
["Ctrl-ArrowUp", gotoPreviousParagraph],
|
||||
["Ctrl-ArrowDown", gotoNextParagraph],
|
||||
["Ctrl-Shift-ArrowUp", selectPreviousParagraph],
|
||||
["Ctrl-Shift-ArrowDown", selectNextParagraph],
|
||||
["Mod-l", () => editor.openLanguageSelector()],
|
||||
].map(([key, run]) => {
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user