mirror of
https://github.com/heyman/heynote.git
synced 2024-11-25 09:23:17 +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)
|
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 blocks = state.facet(blockState)
|
||||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
const block = getNoteBlockFromPos(state, range.head)
|
||||||
const block = getNoteBlockFromPos(state, sel.head)
|
if (range.head === block.content.from) {
|
||||||
if (sel.head === block.content.from) {
|
const index = blocks.indexOf(block)
|
||||||
const index = blocks.indexOf(block)
|
const previousBlockIndex = index > 0 ? index - 1 : 0
|
||||||
const previousBlockIndex = index > 0 ? index - 1 : 0
|
return EditorSelection.cursor(blocks[previousBlockIndex].content.from)
|
||||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.from)
|
} else {
|
||||||
} else {
|
return EditorSelection.cursor(block.content.from)
|
||||||
return EditorSelection.cursor(block.content.from)
|
}
|
||||||
}
|
}
|
||||||
}), state.selection.mainIndex)
|
|
||||||
dispatch(state.update({
|
function nextBlock(state, range) {
|
||||||
selection: newSelection,
|
const blocks = state.facet(blockState)
|
||||||
scrollIntoView: true,
|
const block = getNoteBlockFromPos(state, range.head)
|
||||||
}))
|
if (range.head === block.content.to) {
|
||||||
return true
|
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}) {
|
export function gotoNextBlock({state, dispatch}) {
|
||||||
const blocks = state.facet(blockState)
|
return moveSel(state, dispatch, range => nextBlock(state, range))
|
||||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
}
|
||||||
const block = getNoteBlockFromPos(state, sel.head)
|
export function selectNextBlock({state, dispatch}) {
|
||||||
if (sel.head === block.content.to) {
|
return extendSel(state, dispatch, range => nextBlock(state, range))
|
||||||
const index = blocks.indexOf(block)
|
}
|
||||||
const previousBlockIndex = index < blocks.length - 1 ? index + 1 : index
|
export function gotoPreviousBlock({state, dispatch}) {
|
||||||
return EditorSelection.cursor(blocks[previousBlockIndex].content.to)
|
return moveSel(state, dispatch, range => previousBlock(state, range))
|
||||||
} else {
|
}
|
||||||
return EditorSelection.cursor(block.content.to)
|
export function selectPreviousBlock({state, dispatch}) {
|
||||||
}
|
return extendSel(state, dispatch, range => previousBlock(state, range))
|
||||||
}), state.selection.mainIndex)
|
|
||||||
dispatch(state.update({
|
|
||||||
selection: newSelection,
|
|
||||||
scrollIntoView: true,
|
|
||||||
}))
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gotoPreviousParagraph({state, dispatch}) {
|
|
||||||
|
function previousParagraph(state, range) {
|
||||||
const blocks = state.facet(blockState)
|
const blocks = state.facet(blockState)
|
||||||
const newSelection = EditorSelection.create(state.selection.ranges.map(sel => {
|
let block = getNoteBlockFromPos(state, range.head)
|
||||||
let block = getNoteBlockFromPos(state, sel.head)
|
const blockIndex = blocks.indexOf(block)
|
||||||
const blockIndex = blocks.indexOf(block)
|
|
||||||
|
|
||||||
let seenContentLine = false
|
let seenContentLine = false
|
||||||
let pos
|
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 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) {
|
if (state.doc.lineAt(range.head).from === block.content.from && blockIndex > 0) {
|
||||||
block = blocks[blockIndex - 1]
|
block = blocks[blockIndex - 1]
|
||||||
pos = state.doc.lineAt(block.content.to).from
|
pos = state.doc.lineAt(block.content.to).from
|
||||||
} else {
|
} else {
|
||||||
pos = state.doc.lineAt(sel.head).from
|
pos = state.doc.lineAt(range.head).from
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pos > block.content.from) {
|
while (pos > block.content.from) {
|
||||||
const line = state.doc.lineAt(pos)
|
const line = state.doc.lineAt(pos)
|
||||||
if (line.text.replace(/\s/g, '').length == 0) {
|
if (line.text.replace(/\s/g, '').length == 0) {
|
||||||
if (seenContentLine) {
|
if (seenContentLine) {
|
||||||
return EditorSelection.cursor(line.from)
|
return EditorSelection.cursor(line.from)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
seenContentLine = true
|
|
||||||
}
|
}
|
||||||
// set position to beginning go previous line
|
} else {
|
||||||
pos = state.doc.lineAt(line.from - 1).from
|
seenContentLine = true
|
||||||
}
|
}
|
||||||
return EditorSelection.cursor(block.content.from)
|
// set position to beginning go previous line
|
||||||
}), state.selection.mainIndex)
|
pos = state.doc.lineAt(line.from - 1).from
|
||||||
dispatch(state.update({
|
}
|
||||||
selection: newSelection,
|
return EditorSelection.cursor(block.content.from)
|
||||||
scrollIntoView: true,
|
}
|
||||||
}))
|
|
||||||
return true
|
|
||||||
|
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}) {
|
export function gotoNextParagraph({state, dispatch}) {
|
||||||
const blocks = state.facet(blockState)
|
return moveSel(state, dispatch, range => nextParagraph(state, range))
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 { EditorView, keymap } from "@codemirror/view"
|
||||||
import { EditorSelection } from "@codemirror/state"
|
import { EditorSelection } from "@codemirror/state"
|
||||||
import { indentWithTab, insertTab, indentLess, indentMore, undo, redo } from "@codemirror/commands"
|
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) {
|
export function heynoteKeymap(editor) {
|
||||||
return keymap.of([
|
return keymap.of([
|
||||||
@ -14,8 +23,12 @@ export function heynoteKeymap(editor) {
|
|||||||
["Alt-ArrowDown", moveLineDown],
|
["Alt-ArrowDown", moveLineDown],
|
||||||
["Mod-ArrowUp", gotoPreviousBlock],
|
["Mod-ArrowUp", gotoPreviousBlock],
|
||||||
["Mod-ArrowDown", gotoNextBlock],
|
["Mod-ArrowDown", gotoNextBlock],
|
||||||
|
["Mod-Shift-ArrowUp", selectPreviousBlock],
|
||||||
|
["Mod-Shift-ArrowDown", selectNextBlock],
|
||||||
["Ctrl-ArrowUp", gotoPreviousParagraph],
|
["Ctrl-ArrowUp", gotoPreviousParagraph],
|
||||||
["Ctrl-ArrowDown", gotoNextParagraph],
|
["Ctrl-ArrowDown", gotoNextParagraph],
|
||||||
|
["Ctrl-Shift-ArrowUp", selectPreviousParagraph],
|
||||||
|
["Ctrl-Shift-ArrowDown", selectNextParagraph],
|
||||||
["Mod-l", () => editor.openLanguageSelector()],
|
["Mod-l", () => editor.openLanguageSelector()],
|
||||||
].map(([key, run]) => {
|
].map(([key, run]) => {
|
||||||
return {
|
return {
|
||||||
|
Loading…
Reference in New Issue
Block a user