Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for underline style headings #73

Merged
merged 11 commits into from
May 31, 2023
169 changes: 160 additions & 9 deletions main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import { isExcluded } from './exclusions';

const stockIllegalSymbols = /[\\/:|#^[\]]/g;

// Must be Strings unless settings dialog is updated.
const enum HeadingStyle {
Prefix = 'Prefix',
Underline = 'Underline',
}

interface LinePointer {
lineNumber: number;
text: string;
style: HeadingStyle;
}

interface FilenameHeadingSyncPluginSettings {
Expand All @@ -23,6 +30,9 @@ interface FilenameHeadingSyncPluginSettings {
ignoredFiles: { [key: string]: null };
useFileOpenHook: boolean;
useFileSaveHook: boolean;
newHeadingStyle: HeadingStyle;
replaceStyle: boolean;
underlineString: string;
}

const DEFAULT_SETTINGS: FilenameHeadingSyncPluginSettings = {
Expand All @@ -31,6 +41,9 @@ const DEFAULT_SETTINGS: FilenameHeadingSyncPluginSettings = {
ignoreRegex: '',
useFileOpenHook: true,
useFileSaveHook: true,
newHeadingStyle: HeadingStyle.Prefix,
replaceStyle: false,
underlineString: '===',
};

export default class FilenameHeadingSyncPlugin extends Plugin {
Expand Down Expand Up @@ -222,14 +235,15 @@ export default class FilenameHeadingSyncPlugin extends Plugin {

if (heading !== null) {
if (this.sanitizeHeading(heading.text) !== sanitizedHeading) {
this.replaceLineInFile(
this.replaceHeading(
file,
lines,
heading.lineNumber,
`# ${sanitizedHeading}`,
heading.style,
sanitizedHeading,
);
}
} else this.insertLineInFile(file, lines, start, `# ${sanitizedHeading}`);
} else this.insertHeading(file, lines, start, sanitizedHeading);
});
}

Expand Down Expand Up @@ -267,7 +281,19 @@ export default class FilenameHeadingSyncPlugin extends Plugin {
return {
lineNumber: i,
text: fileLines[i].substring(2),
style: HeadingStyle.Prefix,
};
} else {
if (
fileLines[i + 1] !== undefined &&
fileLines[i + 1].match(/^=+$/) !== null
wilbowma marked this conversation as resolved.
Show resolved Hide resolved
) {
return {
lineNumber: i,
text: fileLines[i],
style: HeadingStyle.Underline,
};
}
}
}
return null; // no heading found
Expand All @@ -292,6 +318,84 @@ export default class FilenameHeadingSyncPlugin extends Plugin {
return text.trim();
}

/**
* Insert the `heading` at `lineNumber` in `file`.
*
* @param {TFile} file the file to modify
* @param {string[]} fileLines array of the file's contents, line by line
* @param {number} lineNumber zero-based index of the line to replace
* @param {string} text the new text
*/
insertHeading(
file: TFile,
fileLines: string[],
lineNumber: number,
heading: string,
) {
const newStyle = this.settings.newHeadingStyle;
if (newStyle === HeadingStyle.Underline) {
this.insertLineInFile(file, fileLines, lineNumber, `${heading}`);

this.insertLineInFile(
file,
fileLines,
lineNumber + 1,
this.settings.underlineString,
);
} else {
wilbowma marked this conversation as resolved.
Show resolved Hide resolved
this.insertLineInFile(file, fileLines, lineNumber, `# ${heading}`);
}
}

/**
* Modified `file` by replacing the heading at `lineNumber` with `newHeading`,
* updating the heading style according the user settings.
*
* @param {TFile} file the file to modify
* @param {string[]} fileLines array of the file's contents, line by line
* @param {number} lineNumber zero-based index of the line to replace
* @param {HeadingStyle} oldStyle the style of the original heading
* @param {string} text the new text
*/
replaceHeading(
file: TFile,
fileLines: string[],
lineNumber: number,
oldStyle: HeadingStyle,
newHeading: string,
) {
const newStyle = this.settings.newHeadingStyle;
const replaceStyle = this.settings.replaceStyle;
// If we replace the style
if (replaceStyle) {
// For underline style, replace heading line, then add underline if not
// already there.
if (newStyle === HeadingStyle.Underline) {
this.replaceLineInFile(file, fileLines, lineNumber, `${newHeading}`);
if (oldStyle === HeadingStyle.Prefix) {
this.insertLineInFile(
file,
fileLines,
lineNumber + 1,
this.settings.underlineString,
);
}
} else {
// If not replacing style, match
if (oldStyle === HeadingStyle.Underline) {
this.replaceLineInFile(file, fileLines, lineNumber, `${newHeading}`);
} else {
this.replaceLineInFile(
file,
fileLines,
lineNumber,
`# ${newHeading}`,
);
}
}
}
}

/**
* Modifies the file by replacing a particular line with new text.
*
Expand Down Expand Up @@ -395,12 +499,10 @@ class FilenameHeadingSyncSettingTab extends PluginSettingTab {

containerEl.createEl('h2', { text: 'Filename Heading Sync' });
containerEl.createEl('p', {
text:
'This plugin will overwrite the first heading found in a file with the filename.',
text: 'This plugin will overwrite the first heading found in a file with the filename.',
});
containerEl.createEl('p', {
text:
'If no header is found, will insert a new one at the first line (after frontmatter).',
text: 'If no header is found, will insert a new one at the first line (after frontmatter).',
});

new Setting(containerEl)
Expand Down Expand Up @@ -468,6 +570,56 @@ class FilenameHeadingSyncSettingTab extends PluginSettingTab {
}),
);

new Setting(containerEl)
.setName('New Heading Style')
.setDesc(
'Which Markdown heading style to use when creating new headings: Prefix ("# Heading") or Underline ("Heading\\n===").',
)
.addDropdown((cb) =>
cb
.addOption(HeadingStyle.Prefix, 'Prefix')
.addOption(HeadingStyle.Underline, 'Underline')
.setValue(this.plugin.settings.newHeadingStyle)
.onChange(async (value) => {
if (value === 'Prefix') {
this.plugin.settings.newHeadingStyle = HeadingStyle.Prefix;
}
if (value === 'Underline') {
this.plugin.settings.newHeadingStyle = HeadingStyle.Underline;
}
await this.plugin.saveSettings();
}),
);

new Setting(containerEl)
.setName('Replace Heading Style')
.setDesc(
'Whether this plugin should replace existing heading styles when updating headings.',
)
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.replaceStyle)
.onChange(async (value) => {
this.plugin.settings.replaceStyle = value;
await this.plugin.saveSettings();
}),
);

new Setting(containerEl)
.setName('Underline String')
.setDesc(
'The string to use when insert Underline-style headings; should be some number of "="s.',
)
.addText((text) =>
text
.setPlaceholder('===')
.setValue(this.plugin.settings.underlineString)
.onChange(async (value) => {
this.plugin.settings.underlineString = value;
await this.plugin.saveSettings();
}),
);

containerEl.createEl('h2', { text: 'Ignored Files By Regex' });
containerEl.createEl('p', {
text: 'All files matching the above RegEx will get listed here',
Expand All @@ -478,8 +630,7 @@ class FilenameHeadingSyncSettingTab extends PluginSettingTab {

containerEl.createEl('h2', { text: 'Manually Ignored Files' });
containerEl.createEl('p', {
text:
'You can ignore files from this plugin by using the "ignore this file" command',
text: 'You can ignore files from this plugin by using the "ignore this file" command',
});

// go over all ignored files and add them
Expand Down