Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CHORE: Added functionality for basic custom language keymaps. #129

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 68 additions & 1 deletion src/editor/block/commands.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EditorSelection } from "@codemirror/state"
import { EditorSelection, ChangeSet } from "@codemirror/state"
import { heynoteEvent, LANGUAGE_CHANGE, CURRENCIES_LOADED, ADD_NEW_BLOCK } from "../annotation.js";
import { blockState, getActiveNoteBlock, getFirstNoteBlock, getLastNoteBlock, getNoteBlockFromPos } from "./block"
import { moveLineDown, moveLineUp } from "./move-lines.js";
Expand Down Expand Up @@ -313,3 +313,70 @@ export function triggerCurrenciesLoaded(state, dispatch) {
annotations: [heynoteEvent.of(CURRENCIES_LOADED)],
}))
}

export function formatBold({state, dispatch}){
let boldSelectionFrom = state.selection.main.from;
let boldSelectionTo = state.selection.main.to;

/**
* Assuring that, if multiple blocks are selected, only
* the active block will be affected by its keymaps
*/
if(state.selection.main.from < getActiveNoteBlock(state).content.from){
boldSelectionFrom = getActiveNoteBlock(state).content.from;
}
if(state.selection.main.to > getActiveNoteBlock(state).content.to){
boldSelectionTo = getActiveNoteBlock(state).content.to;
}
dispatch({
changes: [
ChangeSet.of([
{from: boldSelectionFrom, insert: "**"},
{from: boldSelectionTo, insert: "**"}
], state.doc.length)
],
selection: EditorSelection.cursor(state.selection.main.from == state.selection.main.to ? state.selection.main.from + 2 : state.selection.main.from)
})
return true;
}

export function formatItalic({state, dispatch}){
let italicSelectionFrom = state.selection.main.from;
let italicSelectionTo = state.selection.main.to;

/**
* Assuring that, if multiple blocks are selected, only
* the active block will be affected by its keymaps
*/
if(state.selection.main.from < getActiveNoteBlock(state).content.from){
italicSelectionFrom = getActiveNoteBlock(state).content.from;
}
if(state.selection.main.to > getActiveNoteBlock(state).content.to){
italicSelectionTo = getActiveNoteBlock(state).content.to;
}
dispatch({
changes: [
ChangeSet.of([
{from: italicSelectionFrom, insert: "*"},
{from: italicSelectionTo, insert: "*"}
], state.doc.length)
],
// If there is no text selected, we create a formated text area and move the cursor inside it.
selection: EditorSelection.cursor(state.selection.main.from == state.selection.main.to ? state.selection.main.from + 1 : state.selection.main.from)
})
return true;
}

export function formatTitle({state, dispatch}){
let currentLine = state.doc.lineAt(state.selection.main.head);

dispatch({
changes: [
ChangeSet.of([
{from: currentLine.from, insert: "# "}
], state.doc.length)
],
selection: EditorSelection.cursor(state.selection.main.from == state.selection.main.to ? state.selection.main.from + 2 : currentLine.to)
})
return true;
}
29 changes: 16 additions & 13 deletions src/editor/editor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Annotation, EditorState, Compartment } from "@codemirror/state"
import { EditorView, keymap, drawSelection, ViewPlugin, lineNumbers } from "@codemirror/view"
import { EditorView, keymap as kmp, drawSelection, ViewPlugin, lineNumbers } from "@codemirror/view"
import { indentUnit, forceParsing, foldGutter } from "@codemirror/language"
import { markdown } from "@codemirror/lang-markdown"
import { closeBrackets } from "@codemirror/autocomplete";
Expand All @@ -9,11 +9,11 @@ import { heynoteDark } from "./theme/dark.js"
import { heynoteBase } from "./theme/base.js"
import { customSetup } from "./setup.js"
import { heynoteLang } from "./lang-heynote/heynote.js"
import { noteBlockExtension, blockLineNumbers, blockState } from "./block/block.js"
import { noteBlockExtension, blockLineNumbers, blockState, getActiveNoteBlock } from "./block/block.js"
import { heynoteEvent, SET_CONTENT } from "./annotation.js";
import { changeCurrentBlockLanguage, triggerCurrenciesLoaded } from "./block/commands.js"
import { formatBlockContent } from "./block/format-code.js"
import { heynoteKeymap } from "./keymap.js"
import { heynoteKeymap, languageKeymap } from "./keymap.js"
import { emacsKeymap } from "./emacs.js"
import { heynoteCopyPaste } from "./copy-paste"
import { languageDetection } from "./language-detection/autodetect.js"
Expand All @@ -23,15 +23,6 @@ import { links } from "./links.js"

export const LANGUAGE_SELECTOR_EVENT = "openLanguageSelector"

function getKeymapExtensions(editor, keymap) {
if (keymap === "emacs") {
return emacsKeymap(editor)
} else {
return heynoteKeymap(editor)
}
}


export class HeynoteEditor {
constructor({
element,
Expand All @@ -47,6 +38,7 @@ export class HeynoteEditor {
this.element = element
this.themeCompartment = new Compartment
this.keymapCompartment = new Compartment
this.languageKeymapCompartment = new Compartment
this.lineNumberCompartmentPre = new Compartment
this.lineNumberCompartment = new Compartment
this.foldGutterCompartment = new Compartment
Expand All @@ -57,8 +49,10 @@ export class HeynoteEditor {
const state = EditorState.create({
doc: content || "",
extensions: [
this.keymapCompartment.of(getKeymapExtensions(this, keymap)),
this.keymapCompartment.of(this.getKeymapExtensions(this, keymap)),
this.languageKeymapCompartment.of(kmp.of([])),
heynoteCopyPaste(this),
languageKeymap(this.languageKeymapCompartment),

//minimalSetup,
this.lineNumberCompartment.of(showLineNumberGutter ? [lineNumbers(), blockLineNumbers] : []),
Expand Down Expand Up @@ -116,6 +110,15 @@ export class HeynoteEditor {
}
}

// Changed to a class function to use with languageKeymaps
getKeymapExtensions(editor, keymap) {
if (keymap === "emacs") {
return emacsKeymap(editor)
} else {
return heynoteKeymap(editor)
}
}

getContent() {
return this.view.state.sliceDoc()
}
Expand Down
35 changes: 34 additions & 1 deletion src/editor/keymap.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ import {
selectNextBlock, selectPreviousBlock,
gotoPreviousParagraph, gotoNextParagraph,
selectNextParagraph, selectPreviousParagraph,
newCursorBelow, newCursorAbove,
newCursorBelow, newCursorAbove, formatBold, formatItalic, formatTitle,
} from "./block/commands.js"

import { formatBlockContent } from "./block/format-code.js"
import { EditorState } from "@codemirror/state"
import { getActiveNoteBlock } from "./block/block.js"


export function keymapFromSpec(specs) {
Expand Down Expand Up @@ -57,3 +59,34 @@ export function heynoteKeymap(editor) {
{key:"Ctrl-ArrowDown", run:gotoNextParagraph, shift:selectNextParagraph},
])
}

// Custom keymaps for markdown formatting
const markdownKeymaps = {
language: "markdown",
keymap: keymap.of([
{key:"Ctrl-b", run:formatBold},
{key:"Ctrl-i", run:formatItalic},
{key:"Ctrl-t", run:formatTitle}
])
}

export function languageKeymap(keymapComp){
// First, we check each transaction to see if the block language changed in some way
return EditorState.transactionExtender.of((tr)=>{
if(getActiveNoteBlock(tr.startState).language.name != getActiveNoteBlock(tr.state).language.name){
let targetLanguageKeymap;
// If it did, we assign a new keymap set for the language, or none if not defined
switch(getActiveNoteBlock(tr.state).language.name){
case "markdown":
targetLanguageKeymap = markdownKeymaps.keymap;
break;
default:
targetLanguageKeymap = [];
break;
}
return {
effects: keymapComp.reconfigure(targetLanguageKeymap)
}
}
})
}