Repository: platers/obsidian-linter (ts)

Issue:
Bug: `move-math-block-indicators-to-their-own-line` Incorrectly does not recognize `>` in block quotes as own line
## Describe the Bug

When `move-math-block-indicators-to-their-own-line` is enabled, Linter moves `$$math-blocks$$` outside of block quote environments.

## How to Reproduce

Steps to reproduce the behavior:

1. Enable `move-math-block-indicators-to-their-own-line`
2. Create a new Document
3. Write a block quote with math-block, e.g. 
``` markdown
> $$math$$

```
4. Lint the file multiple times. After three steps, the process converges to
``` markdown
> 
$$
math
$$

```


### First Linting Step
``` markdown
> $$
math
$$

```

### Second Linting Step
``` markdown
> 
$$

math

$$

```
### Final Linting Step
``` markdown
> 
$$
math
$$

```

The process has now converged, further linting does not change the file.

## Expected Behavior

The minimal example

``` markdown
> $$math$$

```

Should be converted into

``` markdown
> $$
> math
> $$

```

## Screenshots

If applicable, add screenshots to help explain your problem.

## Device

I only tested on Desktop

- [x] Desktop
- [ ] Mobile

## Additional Context

The issue does not occur with `empty-line-around-math-blocks`.


Pull request:
Fixed Error Message String, Logging Level Dropdown Text, and Bug with Moving Math Indicators to New Lines
Fixes #560 

Changes Made:
- Added UTs for the scenarios in question
- Updated the logic around moving math block indicators to new lines taking into account the start of the line

Patch:
diff --git a/src/main.ts b/src/main.ts
index f783544..218aa9d 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -431,7 +431,7 @@ export default class LinterPlugin extends Plugin {
       if (useLogTemplateInNotice) {
         new Notice(`${errorMessage} ${error.message}.\n${seeConsoleText}`);
       } else {
-        new Notice(`${error.message}.\nS${seeConsoleText}`);
+        new Notice(`${error.message}.\n${seeConsoleText}`);
       }
     } else {
       new Notice(`${getTextInLanguage('logs.unknown-error')} ${seeConsoleText}`);
diff --git a/src/ui/linter-components/tab-components/debug-tab.ts b/src/ui/linter-components/tab-components/debug-tab.ts
index f2817f9..a5995b2 100644
--- a/src/ui/linter-components/tab-components/debug-tab.ts
+++ b/src/ui/linter-components/tab-components/debug-tab.ts
@@ -7,7 +7,7 @@ import {parseTextToHTMLWithoutOuterParagraph} from 'src/ui/helpers';
 import {logsFromLastRun, setLogLevel} from 'src/utils/logger';
 import {getTextInLanguage, LanguageStringKey} from 'src/lang/helpers';
 
-const logLevels = Object.keys(log.levels) as LanguageStringKey[];
+const logLevels = Object.keys(log.levels) as string[];
 const logLevelInts = Object.values(log.levels);
 
 export class DebugTab extends Tab {
@@ -25,7 +25,7 @@ export class DebugTab extends Tab {
         .setDesc(settingDesc)
         .addDropdown((dropdown) => {
           logLevels.forEach((logLevel, index) => {
-            dropdown.addOption(logLevelInts[index], getTextInLanguage(logLevel));
+            dropdown.addOption(logLevelInts[index], getTextInLanguage('enums.' + logLevel as LanguageStringKey));
           });
           // set value only takes strings so I have to cast the log level to type string in order to get it to work properly
           dropdown.setValue(this.plugin.settings.logLevel + '');
diff --git a/src/utils/mdast.ts b/src/utils/mdast.ts
index 360a9b3..13ec521 100644
--- a/src/utils/mdast.ts
+++ b/src/utils/mdast.ts
@@ -1,7 +1,7 @@
 import {visit} from 'unist-util-visit';
 import type {Position} from 'unist';
 import type {Root} from 'mdast';
-import {hashString53Bit, makeSureContentHasEmptyLinesAddedBeforeAndAfter, replaceTextBetweenStartAndEndWithNewValue} from './strings';
+import {hashString53Bit, makeSureContentHasEmptyLinesAddedBeforeAndAfter, replaceTextBetweenStartAndEndWithNewValue, getStartOfLineIndex} from './strings';
 import {genericLinkRegex} from './regex';
 import {gfmFootnote} from 'micromark-extension-gfm-footnote';
 import {gfmTaskListItem} from 'micromark-extension-gfm-task-list-item';
@@ -559,10 +559,7 @@ export function makeSureMathBlockIndicatorsAreOnTheirOwnLines(text: string, numb
   const mathOpeningIndicatorRegex = new RegExp('^(\\${' + numberOfDollarSignsForMathBlock + ',})(\\n*)');
   const mathEndingIndicatorRegex = new RegExp('(\\n*)(\\${' + numberOfDollarSignsForMathBlock + ',})([^\\$]*)$');
   for (const position of positions) {
-    let mathBlock = text.substring(position.start.offset, position.end.offset);
-    mathBlock = mathBlock.replace(mathOpeningIndicatorRegex, '$1\n');
-    mathBlock= mathBlock.replace(mathEndingIndicatorRegex, '\n$2$3');
-    text = replaceTextBetweenStartAndEndWithNewValue(text, position.start.offset, position.end.offset, mathBlock);
+    text = addBlankLinesAroundStartAndStopMathIndicators(text, position.start.offset, position.end.offset, mathOpeningIndicatorRegex, mathEndingIndicatorRegex);
   }
 
   positions = getPositions(MDAstTypes.InlineMath, text);
@@ -571,11 +568,31 @@ export function makeSureMathBlockIndicatorsAreOnTheirOwnLines(text: string, numb
       continue;
     }
 
-    let mathBlock = text.substring(position.start.offset, position.end.offset);
-    mathBlock = mathBlock.replace(mathOpeningIndicatorRegex, '$1\n');
-    mathBlock= mathBlock.replace(mathEndingIndicatorRegex, '\n$2$3');
-    text = replaceTextBetweenStartAndEndWithNewValue(text, position.start.offset, position.end.offset, mathBlock);
+    text = addBlankLinesAroundStartAndStopMathIndicators(text, position.start.offset, position.end.offset, mathOpeningIndicatorRegex, mathEndingIndicatorRegex);
   }
 
   return text;
 }
+
+function addBlankLinesAroundStartAndStopMathIndicators(text: string, mathBlockStartIndex: number, mathBlockEndIndex: number, mathOpeningIndicatorRegex: RegExp, mathEndingIndicatorRegex: RegExp): string {
+  const startOfLine = text.substring(getStartOfLineIndex(text, mathBlockStartIndex), mathBlockStartIndex) ?? '';
+  let mathBlock = text.substring(mathBlockStartIndex, mathBlockEndIndex);
+  mathBlock = mathBlock.replace(mathOpeningIndicatorRegex, (_: string, $1: string, $2: string = '') => {
+    // a new line is being added
+    if ($2 === '') {
+      return $1 + '\n' + startOfLine;
+    }
+
+    return $1 + '\n';
+  });
+  mathBlock= mathBlock.replace(mathEndingIndicatorRegex, (_: string, $1: string = '', $2: string, $3: string) => {
+    // a new line is being added
+    if ($1 === '') {
+      return '\n' + startOfLine + $2 + $3;
+    }
+
+    return '\n' + $2 + $3;
+  });
+
+  return replaceTextBetweenStartAndEndWithNewValue(text, mathBlockStartIndex, mathBlockEndIndex, mathBlock);
+}
diff --git a/src/utils/strings.ts b/src/utils/strings.ts
index ffe743f..2882263 100644
--- a/src/utils/strings.ts
+++ b/src/utils/strings.ts
@@ -157,3 +157,16 @@ export function convertStringVersionOfEscapeCharactersToEscapeCharacters(val: st
 
   return val;
 }
+
+export function getStartOfLineIndex(text: string, indexToStartFrom: number): number {
+  if (indexToStartFrom < 2) {
+    return indexToStartFrom;
+  }
+
+  let startOfLineIndex = indexToStartFrom;
+  while (startOfLineIndex > 0 && text.charAt(startOfLineIndex - 1) !== '\n') {
+    startOfLineIndex--;
+  }
+
+  return startOfLineIndex;
+}


Test patch:
diff --git a/__tests__/move-math-block-indicators-to-own-line.test.ts b/__tests__/move-math-block-indicators-to-own-line.test.ts
index 7560a7d..2240113 100644
--- a/__tests__/move-math-block-indicators-to-own-line.test.ts
+++ b/__tests__/move-math-block-indicators-to-own-line.test.ts
@@ -19,5 +19,31 @@ ruleTest({
         text here
       `,
     },
+    { // accounts for https://github.com/platers/obsidian-linter/issues/560
+      testName: 'Moving math block indicator to its own line when in a blockquote moves the content to lines with a blockquote indicator at their start for inline math',
+      before: dedent`
+        > $$math$$
+      `,
+      after: dedent`
+        > $$
+        > math
+        > $$
+      `,
+    },
+    {
+      testName: 'Moving math block indicator to its own line when in a blockquote moves the content to lines with a blockquote indicator at their start for math block',
+      before: dedent`
+        > $$
+        > \\boldsymbol{a}=\\begin{bmatrix}a_x \\\\ a_y\\end{bmatrix}$$
+        text here
+      `,
+      after: dedent`
+        > $$
+        > \\boldsymbol{a}=\\begin{bmatrix}a_x \\\\ a_y\\end{bmatrix}
+        > $$
+        text here
+      `,
+    },
+
   ],
 });