Add setting for configuring the default block language and language auto detection

This commit is contained in:
Jonatan Heyman 2024-07-12 14:33:26 +02:00
parent e5d4d31ca2
commit d82b3920d7
8 changed files with 89 additions and 25 deletions

View File

@ -35,6 +35,8 @@ const schema = {
"showInMenu": {type: "boolean", default: false},
"alwaysOnTop": {type: "boolean", default: false},
"bracketClosing": {type: "boolean", default: false},
"defaultBlockLanguage": {type: "string"},
"defaultBlockLanguageAutoDetect": {type: "boolean"},
// when default font settings are used, fontFamily and fontSize is not specified in the
// settings file, so that it's possible for us to change the default settings in the

View File

@ -122,6 +122,8 @@
:bracketClosing="settings.bracketClosing"
:fontFamily="settings.fontFamily"
:fontSize="settings.fontSize"
:defaultBlockLanguage="settings.defaultBlockLanguage || 'text'"
:defaultBlockLanguageAutoDetect="settings.defaultBlockLanguageAutoDetect === undefined ? true : settings.defaultBlockLanguageAutoDetect"
class="editor"
ref="editor"
@openLanguageSelector="openLanguageSelector"

View File

@ -29,6 +29,8 @@
},
fontFamily: String,
fontSize: Number,
defaultBlockLanguage: String,
defaultBlockLanguageAutoDetect: Boolean,
},
components: {},
@ -78,6 +80,7 @@
})
window._heynote_editor = this.editor
window.document.addEventListener("currenciesLoaded", this.onCurrenciesLoaded)
this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect)
// set up buffer change listener
window.heynote.buffer.onChangeCallback((event, content) => {
@ -145,12 +148,18 @@
fontSize() {
this.editor.setFont(this.fontFamily, this.fontSize)
},
defaultBlockLanguage() {
this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect)
},
defaultBlockLanguageAutoDetect() {
this.editor.setDefaultBlockLanguage(this.defaultBlockLanguage, this.defaultBlockLanguageAutoDetect)
},
},
methods: {
setLanguage(language) {
if (language === "auto") {
this.editor.setCurrentLanguage("text", true)
this.editor.setCurrentLanguage(null, true)
} else {
this.editor.setCurrentLanguage(language, false)
}

View File

@ -1,10 +1,14 @@
<script>
import { LANGUAGES } from '../../editor/languages.js'
import KeyboardHotkey from "./KeyboardHotkey.vue"
import TabListItem from "./TabListItem.vue"
import TabContent from "./TabContent.vue"
const defaultFontFamily = window.heynote.defaultFontFamily
const defaultFontSize = window.heynote.defaultFontSize
const defaultDefaultBlockLanguage = "text"
const defaultDefaultBlockLanguageAutoDetect = true
export default {
props: {
@ -39,6 +43,16 @@
bufferPath: this.initialSettings.bufferPath,
fontFamily: this.initialSettings.fontFamily || defaultFontFamily,
fontSize: this.initialSettings.fontSize || defaultFontSize,
languageOptions: LANGUAGES.map(l => {
return {
"value": l.token,
"name": l.token == "text" ? l.name + " (default)" : l.name,
}
}).sort((a, b) => {
return a.name.localeCompare(b.name)
}),
defaultBlockLanguage: this.initialSettings.defaultBlockLanguage || defaultDefaultBlockLanguage,
defaultBlockLanguageAutoDetect: this.initialSettings.defaultBlockLanguageAutoDetect === false ? false : defaultDefaultBlockLanguageAutoDetect,
activeTab: "general",
isWebApp: window.heynote.platform.isWebApp,
@ -89,6 +103,8 @@
bufferPath: this.bufferPath,
fontFamily: this.fontFamily === defaultFontFamily ? undefined : this.fontFamily,
fontSize: this.fontSize === defaultFontSize ? undefined : this.fontSize,
defaultBlockLanguage: this.defaultBlockLanguage === "text" ? undefined : this.defaultBlockLanguage,
defaultBlockLanguageAutoDetect: this.defaultBlockLanguageAutoDetect === true ? undefined : this.defaultBlockLanguageAutoDetect,
})
if (!this.showInDock) {
this.showInMenu = true
@ -255,6 +271,24 @@
</label>
</div>
</div>
<div class="row">
<div class="entry">
<h2>Default Block Language</h2>
<select v-model="defaultBlockLanguage" @change="updateSettings" class="block-language">
<template v-for="lang in languageOptions" :key="lang.value">
<option :selected="lang.value === defaultBlockLanguage" :value="lang.value">{{ lang.name }}</option>
</template>
</select>
<label>
<input
type="checkbox"
v-model="defaultBlockLanguageAutoDetect"
@change="updateSettings"
/>
Auto-detection (default: on)
</label>
</div>
</div>
</TabContent>
<TabContent tab="appearance" :activeTab="activeTab">
@ -417,6 +451,7 @@
overflow-y: auto
select
height: 22px
margin: 4px 0
.row
display: flex
.entry

View File

@ -7,7 +7,11 @@ import { selectAll } from "./select-all.js";
export { moveLineDown, moveLineUp, selectAll }
export const insertNewBlockAtCursor = ({ state, dispatch }) => {
function getBlockDelimiter(defaultToken, autoDetect) {
return `\n∞∞∞${autoDetect ? defaultToken + '-a' : defaultToken}\n`
}
export const insertNewBlockAtCursor = (editor) => ({ state, dispatch }) => {
if (state.readOnly)
return false
@ -16,7 +20,7 @@ export const insertNewBlockAtCursor = ({ state, dispatch }) => {
if (currentBlock) {
delimText = `\n∞∞∞${currentBlock.language.name}${currentBlock.language.auto ? "-a" : ""}\n`
} else {
delimText = "\n∞∞∞text-a\n"
delimText = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect)
}
dispatch(state.replaceSelection(delimText),
{
@ -28,13 +32,12 @@ export const insertNewBlockAtCursor = ({ state, dispatch }) => {
return true;
}
export const addNewBlockBeforeCurrent = ({ state, dispatch }) => {
console.log("addNewBlockBeforeCurrent")
export const addNewBlockBeforeCurrent = (editor) => ({ state, dispatch }) => {
if (state.readOnly)
return false
const block = getActiveNoteBlock(state)
const delimText = "\n∞∞∞text-a\n"
const delimText = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect)
dispatch(state.update({
changes: {
@ -50,12 +53,12 @@ export const addNewBlockBeforeCurrent = ({ state, dispatch }) => {
return true;
}
export const addNewBlockAfterCurrent = ({ state, dispatch }) => {
export const addNewBlockAfterCurrent = (editor) => ({ state, dispatch }) => {
if (state.readOnly)
return false
const block = getActiveNoteBlock(state)
const delimText = "\n∞∞∞text-a\n"
const delimText = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect)
dispatch(state.update({
changes: {
@ -70,12 +73,12 @@ export const addNewBlockAfterCurrent = ({ state, dispatch }) => {
return true;
}
export const addNewBlockBeforeFirst = ({ state, dispatch }) => {
export const addNewBlockBeforeFirst = (editor) => ({ state, dispatch }) => {
if (state.readOnly)
return false
const block = getFirstNoteBlock(state)
const delimText = "\n∞∞∞text-a\n"
const delimText = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect)
dispatch(state.update({
changes: {
@ -91,11 +94,11 @@ export const addNewBlockBeforeFirst = ({ state, dispatch }) => {
return true;
}
export const addNewBlockAfterLast = ({ state, dispatch }) => {
export const addNewBlockAfterLast = (editor) => ({ state, dispatch }) => {
if (state.readOnly)
return false
const block = getLastNoteBlock(state)
const delimText = "\n∞∞∞text-a\n"
const delimText = getBlockDelimiter(editor.defaultBlockToken, editor.defaultBlockAutoDetect)
dispatch(state.update({
changes: {
@ -131,6 +134,10 @@ export function changeLanguageTo(state, dispatch, block, language, auto) {
export function changeCurrentBlockLanguage(state, dispatch, language, auto) {
const block = getActiveNoteBlock(state)
// if language is null, we only want to change the auto-detect flag
if (language === null) {
language = block.language.name
}
changeLanguageTo(state, dispatch, block, language, auto)
}

View File

@ -1,4 +1,4 @@
import { Annotation, EditorState, Compartment } from "@codemirror/state"
import { Annotation, EditorState, Compartment, Facet } from "@codemirror/state"
import { EditorView, keymap, drawSelection, ViewPlugin, lineNumbers } from "@codemirror/view"
import { indentUnit, forceParsing, foldGutter } from "@codemirror/language"
import { markdown } from "@codemirror/lang-markdown"
@ -59,6 +59,8 @@ export class HeynoteEditor {
this.deselectOnCopy = keymap === "emacs"
this.emacsMetaKey = emacsMetaKey
this.fontTheme = new Compartment
this.defaultBlockToken = "text"
this.defaultBlockAutoDetect = true
const state = EditorState.create({
doc: content || "",
@ -84,7 +86,7 @@ export class HeynoteEditor {
}),
heynoteLang(),
noteBlockExtension(this),
languageDetection(() => this.view),
languageDetection(() => this),
// set cursor blink rate to 1 second
drawSelection({cursorBlinkRate:1000}),
@ -206,6 +208,11 @@ export class HeynoteEditor {
})
}
setDefaultBlockLanguage(token, autoDetect) {
this.defaultBlockToken = token
this.defaultBlockAutoDetect = autoDetect
}
formatCurrentBlock() {
formatBlockContent({
state: this.view.state,

View File

@ -48,11 +48,11 @@ export function heynoteKeymap(editor) {
["Mod-x", cutCommand(editor)],
["Tab", indentMore],
["Shift-Tab", indentLess],
["Alt-Shift-Enter", addNewBlockBeforeFirst],
["Mod-Shift-Enter", addNewBlockAfterLast],
["Alt-Enter", addNewBlockBeforeCurrent],
["Mod-Enter", addNewBlockAfterCurrent],
["Mod-Alt-Enter", insertNewBlockAtCursor],
["Alt-Shift-Enter", addNewBlockBeforeFirst(editor)],
["Mod-Shift-Enter", addNewBlockAfterLast(editor)],
["Alt-Enter", addNewBlockBeforeCurrent(editor)],
["Mod-Enter", addNewBlockAfterCurrent(editor)],
["Mod-Alt-Enter", insertNewBlockAtCursor(editor)],
["Mod-a", selectAll],
["Alt-ArrowUp", moveLineUp],
["Alt-ArrowDown", moveLineDown],

View File

@ -25,7 +25,7 @@ function cancelIdleCallbackCompat(id) {
}
}
export function languageDetection(getView) {
export function languageDetection(getEditor) {
const previousBlockContent = {}
let idleCallbackId = null
@ -35,7 +35,8 @@ export function languageDetection(getView) {
if (!event.data.guesslang.language) {
return
}
const view = getView()
const editor = getEditor()
const view = editor.view
const state = view.state
const block = getActiveNoteBlock(state)
const newLang = GUESSLANG_TO_TOKEN[event.data.guesslang.language]
@ -88,11 +89,12 @@ export function languageDetection(getView) {
const content = update.state.doc.sliceString(block.content.from, block.content.to)
if (content === "" && redoDepth(update.state) === 0) {
// if content is cleared, set language to plaintext
const view = getView()
// if content is cleared, set language to default
const editor = getEditor()
const view = editor.view
const block = getActiveNoteBlock(view.state)
if (block.language.name !== "text") {
changeLanguageTo(view.state, view.dispatch, block, "text", true)
if (block.language.name !== editor.defaultBlockToken) {
changeLanguageTo(view.state, view.dispatch, block, editor.defaultBlockToken, true)
}
delete previousBlockContent[idx]
}