Skip to content

Commit

Permalink
Fix #5: imcompatibility with latex suite's 'box current equatoin' com…
Browse files Browse the repository at this point in the history
…mand
  • Loading branch information
RyotaUshio committed Nov 30, 2023
1 parent 222a4e5 commit cf57a13
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 13 deletions.
30 changes: 28 additions & 2 deletions src/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeSpec, EditorState, EditorSelection, ChangeSet, SelectionRange } from '@codemirror/state';
import { ChangeSpec, EditorState, EditorSelection, ChangeSet, SelectionRange, TransactionSpec } from '@codemirror/state';
import { syntaxTree } from '@codemirror/language';

import { isInlineMathBegin, isInlineMathEnd } from './utils';
import { isInlineMathBegin, isInlineMathEnd, printNode } from './utils';


export function getChangesForDeletion(state: EditorState): ChangeSpec {
Expand Down Expand Up @@ -152,3 +152,29 @@ export function handleLatexSuiteTabout(state: EditorState, newSelection: EditorS

return EditorSelection.create(newRanges, newSelection.mainIndex);
}

export function handleLatexSuiteBoxing(state: EditorState, changes: ChangeSet): ChangeSpec | undefined {
const tree = syntaxTree(state);
let changeToReplace: ChangeSpec | undefined;

changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
if (inserted.toString() === "\\boxed{" + state.sliceDoc(fromA, toA) + "}") {
const nodeFrom = tree.cursorAt(fromA, -1).node;
const nodeTo = tree.cursorAt(toA, 1).node;

if (isInlineMathBegin(nodeFrom, state) && isInlineMathEnd(nodeTo, state)) {
// Change generated by Latex Suite's command "box current equation"
if (state.sliceDoc(fromA, fromA + 3) === "{} "
&& state.sliceDoc(toA - 3, toA) === " {}"
) {
// trim the leading "{}" and the trailing " {}"
changeToReplace ={ from: fromA, to: toA, insert: "\\boxed{" + state.sliceDoc(fromA + 3, toA - 3) + "}" };
// Yes, I want to also correct the cursor position as well, but Latex Suite dispatches the replacement
// and cursor position change in two separate transactions, so I can't do it here.
}
}
}
});

return changeToReplace;
}
58 changes: 48 additions & 10 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import { EditorState, Transaction, ChangeSet, TransactionSpec } from '@codemirror/state';
import { EditorState, Transaction } from '@codemirror/state';
import { MarkdownView, Plugin } from 'obsidian';
import { Extension } from '@codemirror/state';

import { DEFAULT_SETTINGS, NoMoreFlickerSettingTab, NoMoreFlickerSettings } from './settings';
import { getChangesForDeletion, getChangesForInsertion, getChangesForSelection, handleLatexSuiteTabout } from './handlers';
import { getChangesForDeletion, getChangesForInsertion, getChangesForSelection, handleLatexSuiteBoxing, handleLatexSuiteTabout } from './handlers';
import { cleanerCallback } from 'cleaner';
import { createViewPlugin } from 'decoration_and_atomic-range';
import { selectionSatisfies } from 'utils';


export default class NoMoreFlicker extends Plugin {
settings: NoMoreFlickerSettings;
/**
* a view plugin that provides
* - decorations to hide braces adjacent to "$"s
* - & atomic ranges to treat each of "${} " and " {}$" as one character
*/
viewPlugin: Extension[] = [];
/**
* Indicates whether the previous transaction was the first of the two transactions
* (1. text replacement & 2. cursor position change) that Latex Suite's "box current equation"
* command produces or not. See the commend in the makeTransactionFilter() method for details.
*/
_latexSuiteBoxing: boolean = false;

async onload() {

Expand Down Expand Up @@ -71,10 +82,41 @@ export default class NoMoreFlicker extends Plugin {
} else if (userEvent === 'delete') {
const changes = getChangesForDeletion(tr.startState);
return [tr, { changes }];
} else if (userEvent === undefined && !tr.docChanged && tr.selection && this.isLatexSuiteTaboutEnabled()) {
// !tr.docChanged is needed to filter out transactions produced by Latex Suite's matrix shortcuts feature
const selection = handleLatexSuiteTabout(tr.startState, tr.selection);
return [tr, { selection }];
} else if (userEvent === undefined) {
/**
* This dirty block is dedicated to keeping compatibility with the following features of Latex Suite:
*
* 1. The "box current equation" command: This command will wrap the equation that the cursor is placed on
* with a `\boxed{}`. When triggered on an inline math of the form "${} ... {}$", the hidden braces are
* accidentally included in the `\boxed{}`.
*
* 2. Tabout: When there is no braces after the cursor, pressing Tab will
* make the cursor escape from `$...$`. When there is a pair of braces after the cursor,
* pressing Tab will move the cursor after the closing brace.
*
* This is problematic because the braces that this plugin inserts right before the closing `$`
* should not be counted as braces by Tabout; it causes the cursor to be placed between " {}" and "$".
*/

if (tr.docChanged && !tr.selection) {
// `tr` is the first transaction (text replacement) of Latex Suite's "box current equation" command
const changes = handleLatexSuiteBoxing(tr.startState, tr.changes);
if (changes) {
this._latexSuiteBoxing = true;
return { changes };
}
} else if (!tr.docChanged && tr.selection) {
// !tr.docChanged is needed to filter out transactions produced by Latex Suite's matrix shortcuts feature
if (this._latexSuiteBoxing) {
// `tr` is the second transaction (text replacement) of Latex Suite's "box current equation" command
this._latexSuiteBoxing = false;
return { selection: { anchor: tr.selection.main.anchor - 3 } }; // 3 == "{} ".length
} else {
// `tr` can be a transaction produced by Tabout
const selection = handleLatexSuiteTabout(tr.startState, tr.selection);
return [tr, { selection }];
}
}
}

return tr;
Expand All @@ -88,10 +130,6 @@ export default class NoMoreFlicker extends Plugin {
);
}

private isLatexSuiteTaboutEnabled(): boolean {
return !!(this.app as any).plugins.plugins['obsidian-latex-suite']?.settings.taboutEnabled;
}

private cleanAllMarkdownViews() {
this.app.workspace.iterateAllLeaves((leaf) => {
if (leaf.view instanceof MarkdownView) {
Expand Down
2 changes: 1 addition & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class NoMoreFlickerSettingTab extends PluginSettingTab {
new Setting(containerEl)
.setName("Disable atomic ranges")
.setDesc(createFragment((el) => {
el.createSpan({ text: "If turned on, atomic ranges to treat \"" });
el.createSpan({ text: "If turned on, atomic ranges to treat each of \"" });
el.createEl("code", { text: "${} " });
el.createSpan({ text: "\" or \"" });
el.createEl("code", { text: " {}$" });
Expand Down

0 comments on commit cf57a13

Please sign in to comment.