Skip to content

Commit

Permalink
Add setting for configuring the default block language and language a…
Browse files Browse the repository at this point in the history
…uto detection
  • Loading branch information
heyman committed Jul 12, 2024
1 parent e5d4d31 commit 715294d
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 25 deletions.
2 changes: 2 additions & 0 deletions electron/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions src/components/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
11 changes: 10 additions & 1 deletion src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
},
fontFamily: String,
fontSize: Number,
defaultBlockLanguage: String,
defaultBlockLanguageAutoDetect: Boolean,
},
components: {},
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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)
}
Expand Down
35 changes: 35 additions & 0 deletions src/components/settings/Settings.vue
Original file line number Diff line number Diff line change
@@ -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: {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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">
Expand Down Expand Up @@ -417,6 +451,7 @@
overflow-y: auto
select
height: 22px
margin: 4px 0
.row
display: flex
.entry
Expand Down
29 changes: 18 additions & 11 deletions src/editor/block/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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),
{
Expand All @@ -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: {
Expand All @@ -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: {
Expand All @@ -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: {
Expand All @@ -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: {
Expand Down Expand Up @@ -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)
}

Expand Down
11 changes: 9 additions & 2 deletions src/editor/editor.js
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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 || "",
Expand All @@ -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}),
Expand Down Expand Up @@ -206,6 +208,11 @@ export class HeynoteEditor {
})
}

setDefaultBlockLanguage(token, autoDetect) {
this.defaultBlockToken = token
this.defaultBlockAutoDetect = autoDetect
}

formatCurrentBlock() {
formatBlockContent({
state: this.view.state,
Expand Down
10 changes: 5 additions & 5 deletions src/editor/keymap.js
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
14 changes: 8 additions & 6 deletions src/editor/language-detection/autodetect.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function cancelIdleCallbackCompat(id) {
}
}

export function languageDetection(getView) {
export function languageDetection(getEditor) {
const previousBlockContent = {}
let idleCallbackId = null

Expand All @@ -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]
Expand Down Expand Up @@ -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]
}
Expand Down

0 comments on commit 715294d

Please sign in to comment.