Compare commits

..

No commits in common. "main" and "v0.3.0" have entirely different histories.
main ... v0.3.0

8 changed files with 36 additions and 75 deletions

View file

@ -1,6 +1,6 @@
{
"name": "syspell",
"version": "0.4.0",
"version": "0.3.0",
"type": "module",
"description": "This SiYuan plugin adds a fully featured grammar and spell checker, powered by LanguageTool.",
"repository": "https://git.massive.box/massivebox/syspell",

View file

@ -2,7 +2,7 @@
"name": "syspell",
"author": "massivebox",
"url": "https://git.massive.box/massivebox/syspell",
"version": "0.4.0",
"version": "0.3.0",
"minAppVersion": "3.0.12",
"backends": [
"windows",

View file

@ -1,5 +1,4 @@
{
"syspell": "SySpell",
"settings":{
"info": {
"title": "Information",

View file

@ -48,7 +48,6 @@ export default class SpellCheckPlugin extends Plugin {
this.eventBus.on('ws-main', async (event) => {
if (event.detail.cmd != 'transactions') {
void this.suggestions.forAllBlocksSuggest(false, true)
return
}

View file

@ -3,7 +3,6 @@ import SpellCheckPlugin from "@/index";
import {getBlockAttrs, setBlockAttrs} from "@/api";
import {Settings} from "@/settings";
import {ProtyleHelper} from "@/protyleHelper";
import {Analytics} from "@/analytics";
export class Menus {
@ -68,9 +67,7 @@ export class Menus {
public async addSettingsToDocMenu(docID: string, menu: subMenu) {
let submenu = []
submenu.push({
menu.addItem({
icon: 'info',
label: this.plugin.i18nx.docMenu.documentStatus,
click: async () => {
@ -89,7 +86,7 @@ export class Menus {
}
})
submenu.push({
menu.addItem({
icon: 'toggle',
label: this.plugin.i18nx.docMenu.toggleSpellCheck,
click: async () => {
@ -107,17 +104,7 @@ export class Menus {
}
})
async function setLang(lang: string, analytics: Analytics) {
const attrs = await getBlockAttrs(docID)
attrs[SpellCheckPlugin.LANGUAGE_ATTR] = lang
await setBlockAttrs(docID, attrs)
void analytics.sendEvent('docmenu-click-setlang-2', {
'language': lang
});
location.reload()
}
submenu.push({
menu.addItem({
icon: 'language',
label: this.plugin.i18nx.docMenu.setDocumentLanguage,
click: async (_, ev: MouseEvent) => {
@ -127,13 +114,29 @@ export class Menus {
langMenu.addItem({
icon: 'autodetect',
label: this.plugin.i18nx.docMenu.autodetectLanguage,
click: async () => setLang('auto', this.plugin.analytics)
click: async () => {
const attrs = await getBlockAttrs(docID)
attrs[SpellCheckPlugin.LANGUAGE_ATTR] = 'auto'
await setBlockAttrs(docID, attrs)
void this.plugin.analytics.sendEvent('docmenu-click-setlang-2', {
'language': 'auto'
});
location.reload()
}
});
languages.forEach(language => {
langMenu.addItem({
icon: 'language',
label: language.name + ' [' + language.longCode + ']',
click: async () => setLang(language.longCode, this.plugin.analytics)
click: async () => {
const attrs = await getBlockAttrs(docID)
attrs[SpellCheckPlugin.LANGUAGE_ATTR] = language.longCode
await setBlockAttrs(docID, attrs)
void this.plugin.analytics.sendEvent('docmenu-click-setlang-2', {
'language': language.longCode
});
location.reload()
}
});
});
langMenu.open({ x: ev.clientX, y: ev.clientY });
@ -141,12 +144,6 @@ export class Menus {
}
})
menu.addItem({
icon: 'spellcheck',
label: this.plugin.i18nx.syspell,
submenu: submenu
})
}
}

View file

@ -41,28 +41,6 @@ export class ProtyleHelper {
return document.querySelector(`div.underline-overlay[for-block-id="${blockID}"]`)
}
public static getElementAtTextIndex(root: Element, index: number): Node {
let currentOffset = 0;
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);
while (walker.nextNode()) {
let node = walker.currentNode
const textLength = node.textContent.length;
if (currentOffset + textLength >= index) {
let parent: Element = node.parentElement;
while (parent && parent != root) {
node = parent
parent = node.parentElement
}
return node; // The element containing this text
}
currentOffset += textLength;
}
return null;
}
// given an element such as a span inside a block, return its blockID
public static getNodeId(el: Element) {
let i = 0;

View file

@ -49,7 +49,7 @@ export class SpellCheckerUI {
// Find the text nodes and character positions
const range = this.createRangeFromCharacterIndices(startIndex, endIndex);
if (range) {
this.createUnderlineFromRange(range);
this.createUnderlineFromRange(range, endIndex - startIndex);
}
}
@ -101,7 +101,7 @@ export class SpellCheckerUI {
return null;
}
private createUnderlineFromRange(range: Range) {
private createUnderlineFromRange(range: Range, charsCount: number) {
const rects = range.getClientRects();
const editorRect = this.block.getBoundingClientRect();
@ -120,9 +120,18 @@ export class SpellCheckerUI {
underline.style.top = (top + 2 + offset.v) + 'px';
underline.style.width = width + 'px';
if(!SpellCheckerUI.checkDontUnderline(width, charsCount)) {
this.overlay.appendChild(underline);
}
}
}
// if the underline is too wide for the number of characters that are underlined, we don't render it
// this is a consequence of using .innerText: things like <img> tags are only a character
private static checkDontUnderline(width: number, charsCount: number) {
const maxWidthPerChar = 16;
return width > maxWidthPerChar * charsCount
}
private static distance(elA: HTMLElement, elB: HTMLElement): {h: number, v: number} {
const rectA = elA.getBoundingClientRect();

View file

@ -20,12 +20,6 @@ export class SuggestionEngine {
private blockStorage: BlockStorage = {};
private plugin: SpellCheckPlugin;
private static blacklisted: string[] = [
"span[data-type='inline-math']",
"span[data-type='img']",
"span[data-type='code']"
];
constructor(plugin: SpellCheckPlugin) {
this.plugin = plugin
}
@ -133,8 +127,7 @@ export class SuggestionEngine {
thisBlock.spellChecker.clearUnderlines()
thisBlock.suggestions?.forEach(suggestion => {
if(this.shouldSuggest(blockID, thisBlock, suggestion) &&
!Settings.isInCustomDictionary(this.suggestionToWrongText(suggestion, blockID), this.plugin.settingsUtil)) {
if(!Settings.isInCustomDictionary(this.suggestionToWrongText(suggestion, blockID), this.plugin.settingsUtil)) {
try {
thisBlock.spellChecker.highlightCharacterRange(suggestion.offset, suggestion.offset + suggestion.length)
}catch (_) {
@ -145,20 +138,6 @@ export class SuggestionEngine {
}
private shouldSuggest(blockID: string, block: StoredBlock, suggestion: Suggestion): boolean {
const element = block.protyle.fastGetBlockElement(blockID)
const eai = ProtyleHelper.getElementAtTextIndex(element, suggestion.offset + suggestion.length)
for(let blacklisted of SuggestionEngine.blacklisted) {
if(eai instanceof Element && eai.matches(blacklisted)) {
return false
}
}
return true
}
public suggestionToWrongText(suggestion: Suggestion, blockID: string): string {
if(!(blockID in this.blockStorage)) {
return