Skip to content

Commit d58e21d

Browse files
committed
feat: working demo prototype of spell grammar check
1 parent 0ebf0e8 commit d58e21d

File tree

5 files changed

+264
-0
lines changed

5 files changed

+264
-0
lines changed

src/extensions/default/DefaultExtensions.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"Phoenix-prettier",
2222
"PrefsCodeHints",
2323
"QuickView",
24+
"SpellGrammarCheck",
2425
"SVGCodeHints",
2526
"UrlCodeHints",
2627
"HealthData"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
define(function (require, exports, module) {
2+
const CodeInspection = brackets.getModule("language/CodeInspection");
3+
4+
const GRAMMAR_CHECKER_NAME = "GrammarChecker";
5+
const supportedExtensions = [
6+
"txt",
7+
"md",
8+
"markdown",
9+
"html",
10+
"htm",
11+
"js",
12+
"ts",
13+
"jsx",
14+
"tsx",
15+
"css",
16+
"less",
17+
"scss"
18+
];
19+
20+
const GRAMMAR_ERRORS = [
21+
{ pattern: /\bthere\s+house\b/gi, suggestion: "their house", message: "Did you mean 'their house'?" },
22+
{ pattern: /\bits\s+self\b/gi, suggestion: "itself", message: "Did you mean 'itself'?" },
23+
{ pattern: /\byour\s+welcome\b/gi, suggestion: "you're welcome", message: "Did you mean 'you're welcome'?" },
24+
{ pattern: /\bto\s+many\b/gi, suggestion: "too many", message: "Did you mean 'too many'?" },
25+
{ pattern: /\bwould\s+of\b/gi, suggestion: "would have", message: "Did you mean 'would have'?" },
26+
{ pattern: /\bcould\s+of\b/gi, suggestion: "could have", message: "Did you mean 'could have'?" },
27+
{ pattern: /\bshould\s+of\b/gi, suggestion: "should have", message: "Did you mean 'should have'?" },
28+
{ pattern: /\balot\b/gi, suggestion: "a lot", message: "Did you mean 'a lot'?" }
29+
];
30+
31+
/**
32+
* Check for grammar errors in the text
33+
*
34+
* @param {string} text - the text to check
35+
* @param {number} lineNumber - the line number (0-based)
36+
* @returns {Array} Array of spell error objects
37+
*/
38+
function checkGrammar(text, lineNumber) {
39+
const errors = [];
40+
41+
GRAMMAR_ERRORS.forEach(function (rule) {
42+
let match;
43+
while ((match = rule.pattern.exec(text)) !== null) {
44+
errors.push({
45+
pos: { line: lineNumber, ch: match.index },
46+
endPos: { line: lineNumber, ch: match.index + match[0].length },
47+
message: rule.message,
48+
type: CodeInspection.Type.META // META type for blue underline
49+
});
50+
}
51+
});
52+
53+
return errors;
54+
}
55+
56+
/**
57+
* This function is responsible to run grammar check on the given text
58+
* TODO: right now we just check the whole file. later need to make it efficient
59+
*
60+
* @param {string} text - The text content to check
61+
* @param {string} fullPath - The full path to the file
62+
* @returns {Object} Results object with errors array
63+
*/
64+
function lintOneFile(text, fullPath) {
65+
const fileExtension = fullPath.split(".").pop().toLowerCase();
66+
67+
if (!supportedExtensions.includes(fileExtension)) {
68+
return null;
69+
}
70+
71+
const lines = text.split("\n");
72+
const allErrors = [];
73+
74+
lines.forEach(function (line, lineIndex) {
75+
const grammarErrors = checkGrammar(line, lineIndex);
76+
allErrors.push(...grammarErrors);
77+
});
78+
79+
if (allErrors.length > 0) {
80+
return { errors: allErrors };
81+
}
82+
83+
return null;
84+
}
85+
86+
/**
87+
* Initialize the grammar checker
88+
* this function is called inside main.js
89+
*/
90+
function init() {
91+
CodeInspection.register("text", {
92+
name: GRAMMAR_CHECKER_NAME,
93+
scanFile: lintOneFile
94+
});
95+
96+
supportedExtensions.forEach(function (languageId) {
97+
CodeInspection.register(languageId, {
98+
name: GRAMMAR_CHECKER_NAME,
99+
scanFile: lintOneFile
100+
});
101+
});
102+
}
103+
104+
exports.init = init;
105+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* GNU AGPL-3.0 License
3+
*
4+
* Copyright (c) 2021 - present core.ai . All rights reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify it
7+
* under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
14+
* for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
18+
*
19+
*/
20+
21+
/**
22+
* Spell and Grammar Check Extension
23+
*/
24+
define(function (require, exports, module) {
25+
const SpellChecker = require("./spell-checker");
26+
const GrammarChecker = require("./grammar-checker");
27+
28+
SpellChecker.init();
29+
GrammarChecker.init();
30+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "SpellGrammarCheck",
3+
"version": "1.0.0",
4+
"dependencies": {}
5+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
define(function (require, exports, module) {
2+
const CodeInspection = brackets.getModule("language/CodeInspection");
3+
4+
const SPELL_CHECKER_NAME = "SpellChecker";
5+
const supportedExtensions = [
6+
"txt",
7+
"md",
8+
"markdown",
9+
"html",
10+
"htm",
11+
"js",
12+
"ts",
13+
"jsx",
14+
"tsx",
15+
"css",
16+
"less",
17+
"scss"
18+
];
19+
20+
const MISSPELLED_WORDS = ["teh", "adn", "wich", "thier"];
21+
22+
/**
23+
* This function is responsible for giving spelling suggestions for a misspelled word
24+
*
25+
* @param {string} word - The misspelled word
26+
* @returns {Array} Array of suggestions
27+
*/
28+
function getSuggestions(word) {
29+
const suggestions = {
30+
teh: ["the"],
31+
adn: ["and"],
32+
wich: ["which"],
33+
thier: ["their"]
34+
};
35+
36+
return suggestions[word] || [word];
37+
}
38+
39+
/**
40+
* Check for spelling errors in the text
41+
*
42+
* @param {string} text - the text to check
43+
* @param {number} lineNumber - the line number (0-based)
44+
* @returns {Array} Array of spell error objects
45+
*/
46+
function checkSpelling(text, lineNumber) {
47+
const errors = [];
48+
const words = text.split(/\s+/);
49+
let currentPos = 0;
50+
51+
words.forEach(function (word) {
52+
// remove punctuation for checking
53+
const cleanWord = word.replace(/[^\w]/g, "").toLowerCase();
54+
55+
if (cleanWord && MISSPELLED_WORDS.includes(cleanWord)) {
56+
const wordStart = text.indexOf(word, currentPos);
57+
const wordEnd = wordStart + word.length;
58+
59+
errors.push({
60+
pos: { line: lineNumber, ch: wordStart },
61+
endPos: { line: lineNumber, ch: wordEnd },
62+
message: `
63+
"${word}" may be misspelled. Did you mean one of: ${getSuggestions(cleanWord).join(", ")}?
64+
`,
65+
type: CodeInspection.Type.SPELL
66+
});
67+
}
68+
currentPos = text.indexOf(word, currentPos) + word.length;
69+
});
70+
71+
return errors;
72+
}
73+
74+
/**
75+
* This function is responsible to run spell check on the given text
76+
* TODO: right now we just check the whole file. later need to make it efficient
77+
*
78+
* @param {string} text - The text content to check
79+
* @param {string} fullPath - The full path to the file
80+
* @returns {Object} Results object with errors array
81+
*/
82+
function lintOneFile(text, fullPath) {
83+
const fileExtension = fullPath.split(".").pop().toLowerCase();
84+
85+
if (!supportedExtensions.includes(fileExtension)) {
86+
return null;
87+
}
88+
89+
const lines = text.split("\n");
90+
const allErrors = [];
91+
92+
lines.forEach(function (line, lineIndex) {
93+
const spellErrors = checkSpelling(line, lineIndex);
94+
allErrors.push(...spellErrors);
95+
});
96+
97+
if (allErrors.length > 0) {
98+
return { errors: allErrors };
99+
}
100+
101+
return null;
102+
}
103+
104+
/**
105+
* Initialize the spell checker
106+
* this function is called inside main.js
107+
*/
108+
function init() {
109+
CodeInspection.register("text", {
110+
name: SPELL_CHECKER_NAME,
111+
scanFile: lintOneFile
112+
});
113+
114+
supportedExtensions.forEach(function (languageId) {
115+
CodeInspection.register(languageId, {
116+
name: SPELL_CHECKER_NAME,
117+
scanFile: lintOneFile
118+
});
119+
});
120+
}
121+
122+
exports.init = init;
123+
});

0 commit comments

Comments
 (0)