diff --git a/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.tsx b/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.tsx index 5c7168347..c9331c29e 100644 --- a/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.tsx +++ b/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/Editor.tsx @@ -1,7 +1,5 @@ import * as React from 'react'; import { useEffect, useImperativeHandle, useState, useRef, useCallback, forwardRef } from 'react'; - -const CodeMirror = require('codemirror'); import 'codemirror/addon/comment/comment'; import 'codemirror/addon/dialog/dialog'; import 'codemirror/addon/edit/closebrackets'; @@ -15,6 +13,7 @@ import useLineSorting from './utils/useLineSorting'; import 'codemirror/keymap/emacs'; import 'codemirror/keymap/vim'; +import 'codemirror/keymap/sublime'; // Used for swapLineUp and swapLineDown import 'codemirror/mode/gfm/gfm'; import 'codemirror/mode/xml/xml'; @@ -26,6 +25,8 @@ import 'codemirror/mode/clike/clike'; import 'codemirror/mode/diff/diff'; import 'codemirror/mode/sql/sql'; +const CodeMirror = require('codemirror'); + export interface CancelledKeys { mac: string[], default: string[], @@ -134,6 +135,12 @@ function Editor(props: EditorProps, ref: any) { extraKeys: { 'Enter': 'insertListElement', 'Ctrl-/': 'toggleComment', 'Ctrl-Alt-S': 'sortSelectedLines', + 'Alt-Up': 'swapLineUp', + 'Alt-Down': 'swapLineDown', + 'Cmd-/': 'toggleComment', + 'Cmd-Opt-S': 'sortSelectedLines', + 'Opt-Up': 'swapLineUp', + 'Opt-Down': 'swapLineDown', 'Tab': 'smartListIndent', 'Shift-Tab': 'smartListUnindent' }, }; diff --git a/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.ts b/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.ts index 8714d1d31..222ce6547 100644 --- a/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.ts +++ b/ElectronClient/gui/NoteEditor/NoteBody/CodeMirror/utils/useListIdent.ts @@ -47,16 +47,16 @@ export default function useListIdent(CodeMirror: any) { return currentToken; } - // Gets the first non-whitespace token locationof a list - function getListSpan(listTokens: any) { + // Gets the character coordinates of the start and end of a list token + function getListSpan(listTokens: any, line: string) { let start = listTokens[0].start; - const end = listTokens[listTokens.length - 1].end; + const token = extractListToken(line); if (listTokens.length > 1 && listTokens[0].string.match(/\s/)) { start = listTokens[1].start; } - return { start: start, end: end }; + return { start: start, end: start + token.length }; } CodeMirror.commands.smartListIndent = function(cm: any) { @@ -74,7 +74,7 @@ export default function useListIdent(CodeMirror: any) { } else { if (olLineNumber(line)) { const tokens = cm.getLineTokens(anchor.line); - const { start, end } = getListSpan(tokens); + const { start, end } = getListSpan(tokens, line); // Resets numbered list to 1. cm.replaceRange('1. ', { line: anchor.line, ch: start }, { line: anchor.line, ch: end }); } @@ -99,9 +99,9 @@ export default function useListIdent(CodeMirror: any) { } else { const newToken = newListToken(cm, anchor.line); const tokens = cm.getLineTokens(anchor.line); - const { start, end } = getListSpan(tokens); + const { start, end } = getListSpan(tokens, line); - cm.replaceRange(newToken, { line: anchor.line, ch: start }, { line: anchor.line, ch: end }); + cm.replaceRange(newToken, { line: anchor.line, ch: start }, { line: anchor.line, ch: end }); cm.indentLine(anchor.line, 'subtract'); } @@ -126,7 +126,15 @@ export default function useListIdent(CodeMirror: any) { cm.replaceRange('', { line: anchor.line, ch: 0 }, anchor); } } else { - cm.execCommand('newlineAndIndentContinueMarkdownList'); + // Disable automatic indent for html/xml outside of codeblocks + const state = cm.getTokenAt(anchor).state; + const mode = cm.getModeAt(anchor); + // html/xml inside of a codeblock is fair game for auto-indent + if (mode.name !== 'xml' || state.overlay.codeBlock) { + cm.execCommand('newlineAndIndentContinueMarkdownList'); + } else { + cm.replaceSelection('\n'); + } } } }; diff --git a/ReactNativeClient/lib/markdownUtils.js b/ReactNativeClient/lib/markdownUtils.js index 69a15488a..7291713a9 100644 --- a/ReactNativeClient/lib/markdownUtils.js +++ b/ReactNativeClient/lib/markdownUtils.js @@ -5,7 +5,7 @@ const { setupLinkify } = require('lib/joplin-renderer'); const removeMarkdown = require('remove-markdown'); // Taken from codemirror/addon/edit/continuelist.js -const listRegex = /^(\s*)([*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/; +const listRegex = /^(\s*)([*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]\s))(\s*)/; const emptyListRegex = /^(\s*)([*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/; const markdownUtils = {