feat: add setting for line wrapping

Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
Tilman Vatteroth 2023-04-05 19:23:10 +02:00
parent 4790c7cd1b
commit e368203e16
8 changed files with 74 additions and 4 deletions

View file

@ -612,6 +612,10 @@
"syncScroll": { "syncScroll": {
"label": "Sync Scrolling", "label": "Sync Scrolling",
"help": "Synchronizes the scroll state of editor and rendering view." "help": "Synchronizes the scroll state of editor and rendering view."
},
"lineWrapping": {
"label": "Line Wrapping",
"help": "Breaks long lines so they're visible without scrolling."
} }
}, },
"global": { "global": {

View file

@ -13,6 +13,7 @@ import type { ScrollProps } from '../synced-scroll/scroll-props'
import styles from './extended-codemirror/codemirror.module.scss' import styles from './extended-codemirror/codemirror.module.scss'
import { useCodeMirrorAutocompletionsExtension } from './hooks/codemirror-extensions/use-code-mirror-autocompletions-extension' import { useCodeMirrorAutocompletionsExtension } from './hooks/codemirror-extensions/use-code-mirror-autocompletions-extension'
import { useCodeMirrorFileInsertExtension } from './hooks/codemirror-extensions/use-code-mirror-file-insert-extension' import { useCodeMirrorFileInsertExtension } from './hooks/codemirror-extensions/use-code-mirror-file-insert-extension'
import { useCodeMirrorLineWrappingExtension } from './hooks/codemirror-extensions/use-code-mirror-line-wrapping-extension'
import { useCodeMirrorRemoteCursorsExtension } from './hooks/codemirror-extensions/use-code-mirror-remote-cursor-extensions' import { useCodeMirrorRemoteCursorsExtension } from './hooks/codemirror-extensions/use-code-mirror-remote-cursor-extensions'
import { useCodeMirrorScrollWatchExtension } from './hooks/codemirror-extensions/use-code-mirror-scroll-watch-extension' import { useCodeMirrorScrollWatchExtension } from './hooks/codemirror-extensions/use-code-mirror-scroll-watch-extension'
import { useCodeMirrorSpellCheckExtension } from './hooks/codemirror-extensions/use-code-mirror-spell-check-extension' import { useCodeMirrorSpellCheckExtension } from './hooks/codemirror-extensions/use-code-mirror-spell-check-extension'
@ -39,7 +40,6 @@ import { markdown, markdownLanguage } from '@codemirror/lang-markdown'
import { languages } from '@codemirror/language-data' import { languages } from '@codemirror/language-data'
import { lintGutter } from '@codemirror/lint' import { lintGutter } from '@codemirror/lint'
import { oneDark } from '@codemirror/theme-one-dark' import { oneDark } from '@codemirror/theme-one-dark'
import { EditorView } from '@codemirror/view'
import ReactCodeMirror from '@uiw/react-codemirror' import ReactCodeMirror from '@uiw/react-codemirror'
import React, { useEffect, useMemo } from 'react' import React, { useEffect, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
@ -67,6 +67,7 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
const tablePasteExtensions = useCodeMirrorTablePasteExtension() const tablePasteExtensions = useCodeMirrorTablePasteExtension()
const fileInsertExtension = useCodeMirrorFileInsertExtension() const fileInsertExtension = useCodeMirrorFileInsertExtension()
const spellCheckExtension = useCodeMirrorSpellCheckExtension() const spellCheckExtension = useCodeMirrorSpellCheckExtension()
const lineWrappingExtension = useCodeMirrorLineWrappingExtension()
const cursorActivityExtension = useCursorActivityCallback() const cursorActivityExtension = useCursorActivityCallback()
const autoCompletionExtension = useCodeMirrorAutocompletionsExtension() const autoCompletionExtension = useCodeMirrorAutocompletionsExtension()
@ -95,7 +96,7 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
codeLanguages: (input) => findLanguageByCodeBlockName(languages, input) codeLanguages: (input) => findLanguageByCodeBlockName(languages, input)
}), }),
remoteCursorsExtension, remoteCursorsExtension,
EditorView.lineWrapping, lineWrappingExtension,
editorScrollExtension, editorScrollExtension,
tablePasteExtensions, tablePasteExtensions,
fileInsertExtension, fileInsertExtension,
@ -115,7 +116,8 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
cursorActivityExtension, cursorActivityExtension,
updateViewContextExtension, updateViewContextExtension,
yjsExtension, yjsExtension,
spellCheckExtension spellCheckExtension,
lineWrappingExtension
] ]
) )

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useApplicationState } from '../../../../../hooks/common/use-application-state'
import type { Extension } from '@codemirror/state'
import { EditorView } from '@codemirror/view'
import { useMemo } from 'react'
/**
* Creates a {@link Extension codemirror extension} that activates or deactivates line wrapping.
*/
export const useCodeMirrorLineWrappingExtension = (): Extension => {
const lineWrapping = useApplicationState((state) => state.editorConfig.lineWrapping)
return useMemo(() => (lineWrapping ? EditorView.lineWrapping : []), [lineWrapping])
}

View file

@ -5,6 +5,7 @@
*/ */
import { SettingLine } from '../utils/setting-line' import { SettingLine } from '../utils/setting-line'
import { LigatureSettingButtonGroup } from './ligature-setting-button-group' import { LigatureSettingButtonGroup } from './ligature-setting-button-group'
import { LineWrappingSettingButtonGroup } from './line-wrapping-setting-button-group'
import { SmartPasteSettingButtonGroup } from './smart-paste-setting-button-group' import { SmartPasteSettingButtonGroup } from './smart-paste-setting-button-group'
import { SyncScrollSettingButtonGroup } from './sync-scroll-setting-button-group' import { SyncScrollSettingButtonGroup } from './sync-scroll-setting-button-group'
import React from 'react' import React from 'react'
@ -28,6 +29,9 @@ export const EditorSettingsTabContent: React.FC = () => {
<SettingLine i18nKey={'editor.syncScroll'}> <SettingLine i18nKey={'editor.syncScroll'}>
<SyncScrollSettingButtonGroup /> <SyncScrollSettingButtonGroup />
</SettingLine> </SettingLine>
<SettingLine i18nKey={'editor.lineWrapping'}>
<LineWrappingSettingButtonGroup />
</SettingLine>
</ListGroup> </ListGroup>
) )
} }

View file

@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { useApplicationState } from '../../../../hooks/common/use-application-state'
import { setEditorLineWrapping } from '../../../../redux/editor/methods'
import { OnOffButtonGroup } from '../utils/on-off-button-group'
import React from 'react'
/**
* Allows to change if line wrapping should be used or not in the editor.
*/
export const LineWrappingSettingButtonGroup: React.FC = () => {
const enabled = useApplicationState((state) => state.editorConfig.lineWrapping)
return <OnOffButtonGroup value={enabled} onSelect={setEditorLineWrapping} />
}

View file

@ -8,6 +8,7 @@ import { Logger } from '../../utils/logger'
import type { import type {
EditorConfig, EditorConfig,
SetEditorLigaturesAction, SetEditorLigaturesAction,
SetEditorLineWrappingAction,
SetEditorSmartPasteAction, SetEditorSmartPasteAction,
SetEditorSyncScrollAction SetEditorSyncScrollAction
} from './types' } from './types'
@ -44,6 +45,14 @@ export const setEditorSyncScroll = (syncScroll: boolean): void => {
store.dispatch(action) store.dispatch(action)
} }
export const setEditorLineWrapping = (lineWrapping: boolean): void => {
const action: SetEditorLineWrappingAction = {
type: EditorConfigActionType.SET_LINE_WRAPPING,
lineWrapping
}
store.dispatch(action)
}
export const setEditorLigatures = (ligatures: boolean): void => { export const setEditorLigatures = (ligatures: boolean): void => {
const action: SetEditorLigaturesAction = { const action: SetEditorLigaturesAction = {
type: EditorConfigActionType.SET_LIGATURES, type: EditorConfigActionType.SET_LIGATURES,

View file

@ -12,7 +12,8 @@ const initialState: EditorConfig = {
ligatures: true, ligatures: true,
syncScroll: true, syncScroll: true,
smartPaste: true, smartPaste: true,
spellCheck: false spellCheck: false,
lineWrapping: true
} }
const getInitialState = (): EditorConfig => { const getInitialState = (): EditorConfig => {
@ -53,6 +54,13 @@ export const EditorConfigReducer: Reducer<EditorConfig, EditorConfigActions> = (
} }
saveToLocalStorage(newState) saveToLocalStorage(newState)
return newState return newState
case EditorConfigActionType.SET_LINE_WRAPPING:
newState = {
...state,
lineWrapping: action.lineWrapping
}
saveToLocalStorage(newState)
return newState
default: default:
return state return state
} }

View file

@ -9,6 +9,7 @@ export enum EditorConfigActionType {
SET_EDITOR_VIEW_MODE = 'editor/view-mode/set', SET_EDITOR_VIEW_MODE = 'editor/view-mode/set',
SET_SYNC_SCROLL = 'editor/syncScroll/set', SET_SYNC_SCROLL = 'editor/syncScroll/set',
SET_LIGATURES = 'editor/preferences/setLigatures', SET_LIGATURES = 'editor/preferences/setLigatures',
SET_LINE_WRAPPING = 'editor/preferences/setLineWrapping',
SET_SMART_PASTE = 'editor/preferences/setSmartPaste', SET_SMART_PASTE = 'editor/preferences/setSmartPaste',
SET_SPELL_CHECK = 'editor/preferences/setSpellCheck' SET_SPELL_CHECK = 'editor/preferences/setSpellCheck'
} }
@ -18,14 +19,21 @@ export interface EditorConfig {
ligatures: boolean ligatures: boolean
smartPaste: boolean smartPaste: boolean
spellCheck: boolean spellCheck: boolean
lineWrapping: boolean
} }
export type EditorConfigActions = export type EditorConfigActions =
| SetEditorSyncScrollAction | SetEditorSyncScrollAction
| SetEditorLigaturesAction | SetEditorLigaturesAction
| SetEditorSmartPasteAction | SetEditorSmartPasteAction
| SetEditorLineWrappingAction
| SetSpellCheckAction | SetSpellCheckAction
export interface SetEditorLineWrappingAction extends Action<EditorConfigActionType> {
type: EditorConfigActionType.SET_LINE_WRAPPING
lineWrapping: boolean
}
export interface SetEditorSyncScrollAction extends Action<EditorConfigActionType> { export interface SetEditorSyncScrollAction extends Action<EditorConfigActionType> {
type: EditorConfigActionType.SET_SYNC_SCROLL type: EditorConfigActionType.SET_SYNC_SCROLL
syncScroll: boolean syncScroll: boolean