mirror of
https://github.com/dylanarmstrong/obsidian-prettier-plugin.git
synced 2026-07-22 05:46:07 +00:00
feat: update editor directly to fix jumping cursor
This commit is contained in:
parent
fbdfcaee0e
commit
5add7ef706
6 changed files with 84 additions and 30 deletions
|
|
@ -7,5 +7,5 @@
|
|||
"isDesktopOnly": false,
|
||||
"minAppVersion": "0.15.0",
|
||||
"name": "Format Automatically with Prettier",
|
||||
"version": "0.1.8"
|
||||
"version": "0.2.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
{
|
||||
"author": "Dylan Armstrong<dylan@dylan.is>",
|
||||
"dependencies": {
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"obsidian": "^1.8.7",
|
||||
"prettier": "^3.5.3"
|
||||
},
|
||||
"description": "This is a formatting plugin for Obsidian (https://obsidian.md)",
|
||||
"devDependencies": {
|
||||
"@codemirror/view": "^6.36.8",
|
||||
"@dylanarmstrong/eslint-config": "^0.8.0",
|
||||
"@eslint/js": "^9.27.0",
|
||||
"@types/diff-match-patch": "^1.0.36",
|
||||
"@types/node": "^22.15.21",
|
||||
"builtin-modules": "5.0.0",
|
||||
"esbuild": "0.25.4",
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
diff-match-patch:
|
||||
specifier: ^1.0.5
|
||||
version: 1.0.5
|
||||
obsidian:
|
||||
specifier: ^1.8.7
|
||||
version: 1.8.7(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)
|
||||
|
|
@ -15,12 +18,18 @@ importers:
|
|||
specifier: ^3.5.3
|
||||
version: 3.5.3
|
||||
devDependencies:
|
||||
'@codemirror/view':
|
||||
specifier: ^6.36.8
|
||||
version: 6.36.8
|
||||
'@dylanarmstrong/eslint-config':
|
||||
specifier: ^0.8.0
|
||||
version: 0.8.0(eslint@9.27.0)
|
||||
'@eslint/js':
|
||||
specifier: ^9.27.0
|
||||
version: 9.27.0
|
||||
'@types/diff-match-patch':
|
||||
specifier: ^1.0.36
|
||||
version: 1.0.36
|
||||
'@types/node':
|
||||
specifier: ^22.15.21
|
||||
version: 22.15.21
|
||||
|
|
@ -301,6 +310,9 @@ packages:
|
|||
'@types/codemirror@5.60.8':
|
||||
resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==}
|
||||
|
||||
'@types/diff-match-patch@1.0.36':
|
||||
resolution: {integrity: sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==}
|
||||
|
||||
'@types/estree@1.0.7':
|
||||
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
|
||||
|
||||
|
|
@ -454,6 +466,9 @@ packages:
|
|||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
diff-match-patch@1.0.5:
|
||||
resolution: {integrity: sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==}
|
||||
|
||||
electron-to-chromium@1.5.157:
|
||||
resolution: {integrity: sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w==}
|
||||
|
||||
|
|
@ -1036,6 +1051,8 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/tern': 0.23.9
|
||||
|
||||
'@types/diff-match-patch@1.0.36': {}
|
||||
|
||||
'@types/estree@1.0.7': {}
|
||||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
|
@ -1209,6 +1226,8 @@ snapshots:
|
|||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
diff-match-patch@1.0.5: {}
|
||||
|
||||
electron-to-chromium@1.5.157: {}
|
||||
|
||||
esbuild@0.25.4:
|
||||
|
|
|
|||
5
src/@types/obsidian-ex.d.ts
vendored
5
src/@types/obsidian-ex.d.ts
vendored
|
|
@ -1,4 +1,5 @@
|
|||
import 'obsidian';
|
||||
import { EditorView } from '@codemirror/view';
|
||||
|
||||
declare module 'obsidian' {
|
||||
interface App {
|
||||
|
|
@ -12,6 +13,10 @@ declare module 'obsidian' {
|
|||
};
|
||||
}
|
||||
|
||||
interface Editor {
|
||||
cm?: EditorView;
|
||||
}
|
||||
|
||||
interface Vault {
|
||||
getConfig(id: string): boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import DiffMatchPatch from 'diff-match-patch';
|
||||
import { EditorPosition, Plugin } from 'obsidian';
|
||||
|
||||
import * as markdownPlugin from 'prettier/plugins/markdown';
|
||||
|
|
@ -17,22 +18,11 @@ const DEFAULT_SETTINGS: PrettierPluginSettings = {
|
|||
useTabs: true,
|
||||
};
|
||||
|
||||
// Taken from https://github.com/alexgavrusev/obsidian-format-with-prettier/blob/master/src/cursor-position-utils.ts
|
||||
// If the cursor is on line i, on character j, the offset
|
||||
// is j plus sum of lengths (incl. the \n at the end) of lines 0..(i - 1)
|
||||
const toOffset = (position: EditorPosition, text: string): number =>
|
||||
text
|
||||
.split('\n')
|
||||
.slice(0, position.line)
|
||||
.reduce((accumulator, line) => accumulator + line.length + 1, position.ch);
|
||||
|
||||
const fromOffset = (offset: number, text: string): EditorPosition => {
|
||||
const textUpToOffset = text.slice(0, offset);
|
||||
const newLines = textUpToOffset.split('\n');
|
||||
|
||||
const getPosition = (text: string): EditorPosition => {
|
||||
const lines = text.split('\n');
|
||||
return {
|
||||
ch: newLines?.at(-1)?.length || 0,
|
||||
line: newLines.length - 1,
|
||||
ch: lines.at(-1)?.length ?? 0,
|
||||
line: lines.length - 1,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -43,28 +33,64 @@ export default class PrettierPlugin extends Plugin {
|
|||
|
||||
private async format() {
|
||||
const editor = this.app.workspace.activeEditor?.editor;
|
||||
if (!editor) {
|
||||
if (!editor || !editor.cm) {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
const text = editor.getValue();
|
||||
if (text && file) {
|
||||
const position = editor.getCursor();
|
||||
const cursorOffset = toOffset(position, text);
|
||||
const formattedText = await prettier.format(text, {
|
||||
embeddedLanguageFormatting: 'auto',
|
||||
filepath: file.path,
|
||||
parser: 'markdown',
|
||||
plugins: [markdownPlugin],
|
||||
tabWidth: this.settings.tabWidth,
|
||||
useTabs: this.settings.useTabs,
|
||||
});
|
||||
|
||||
const { cursorOffset: formattedCursorOffset, formatted: formattedText } =
|
||||
await prettier.formatWithCursor(text, {
|
||||
cursorOffset,
|
||||
filepath: file.path,
|
||||
parser: 'markdown',
|
||||
plugins: [markdownPlugin],
|
||||
tabWidth: this.settings.tabWidth,
|
||||
useTabs: this.settings.useTabs,
|
||||
});
|
||||
// Switched to using DiffMatchPatch after I saw it here:
|
||||
// https://github.com/platers/obsidian-linter
|
||||
// And this style of updating the editor stops my cursor from jumping
|
||||
// around. Also, it keeps sections toggled if I've closed them.
|
||||
|
||||
editor.setValue(formattedText);
|
||||
editor.setCursor(fromOffset(formattedCursorOffset, formattedText));
|
||||
// eslint-disable-next-line new-cap
|
||||
const dmp = new DiffMatchPatch.diff_match_patch();
|
||||
const changes = dmp.diff_main(text, formattedText);
|
||||
|
||||
let currentText = '';
|
||||
for (const change of changes) {
|
||||
const [type, value] = change;
|
||||
|
||||
if (type === DiffMatchPatch.DIFF_INSERT) {
|
||||
editor.cm.dispatch({
|
||||
changes: [
|
||||
{
|
||||
from: editor.posToOffset(getPosition(currentText)),
|
||||
insert: value,
|
||||
},
|
||||
],
|
||||
filter: false,
|
||||
});
|
||||
currentText += value;
|
||||
} else if (type === DiffMatchPatch.DIFF_DELETE) {
|
||||
const start = getPosition(currentText);
|
||||
const end = getPosition(currentText + value);
|
||||
|
||||
editor.cm.dispatch({
|
||||
changes: [
|
||||
{
|
||||
from: editor.posToOffset(start),
|
||||
insert: '',
|
||||
to: editor.posToOffset(end),
|
||||
},
|
||||
],
|
||||
filter: false,
|
||||
});
|
||||
} else {
|
||||
currentText += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": ".",
|
||||
"importHelpers": true,
|
||||
"inlineSourceMap": true,
|
||||
|
|
|
|||
Loading…
Reference in a new issue