✨ grammar checker
This commit is contained in:
@@ -363,6 +363,34 @@ export function AnalysisToolbar(): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
const runGrammar = async (): Promise<void> => {
|
||||
if (!hasFile || isAILoading) return
|
||||
setAILoading(true)
|
||||
setAIError(null)
|
||||
setAnalysisMode('none')
|
||||
try {
|
||||
const matches = await window.api.checkGrammar(activeFileContent)
|
||||
const newAnnotations = matches.map((m) => {
|
||||
const matched = activeFileContent.slice(m.offset, m.offset + m.length)
|
||||
return {
|
||||
id: `grammar-${m.offset}-${m.ruleId}`,
|
||||
type: 'grammar' as const,
|
||||
from: m.offset,
|
||||
to: m.offset + m.length,
|
||||
matchedText: matched,
|
||||
message: m.message,
|
||||
suggestion: m.replacement ?? undefined,
|
||||
}
|
||||
})
|
||||
const existing = useEditorStore.getState().annotations.filter((a) => a.type !== 'grammar')
|
||||
setAnnotations([...existing, ...newAnnotations])
|
||||
} catch (err) {
|
||||
setAIError(err instanceof Error ? err.message : 'Grammar check failed')
|
||||
} finally {
|
||||
setAILoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const passiveCount = annotations.filter((a) => a.type === 'passive_voice').length
|
||||
const pastProgressiveCount = annotations.filter((a) => a.type === 'past_progressive').length
|
||||
const weakVerbsCount = annotations.filter((a) => a.type === 'weak_verbs').length
|
||||
@@ -371,7 +399,8 @@ export function AnalysisToolbar(): JSX.Element {
|
||||
const styleCount = annotations.filter((a) => a.type === 'style').length
|
||||
const showTellCount = annotations.filter((a) => a.type === 'show_tell').length
|
||||
const critiqueCount = annotations.filter((a) => a.type === 'critique').length
|
||||
const totalCount = passiveCount + pastProgressiveCount + weakVerbsCount + clichesCount + consistencyCount + styleCount + showTellCount + critiqueCount
|
||||
const grammarCount = annotations.filter((a) => a.type === 'grammar').length
|
||||
const totalCount = passiveCount + pastProgressiveCount + weakVerbsCount + clichesCount + consistencyCount + styleCount + showTellCount + critiqueCount + grammarCount
|
||||
const anyActive = Boolean(analysisMode)
|
||||
const sentenceStats = activeFileContent ? computeSentenceStats(activeFileContent) : null
|
||||
const paragraphRhythm = activeFileContent ? computeParagraphRhythm(activeFileContent) : []
|
||||
@@ -506,6 +535,14 @@ export function AnalysisToolbar(): JSX.Element {
|
||||
<span>Critique</span>
|
||||
{critiqueCount > 0 && <span className="toolbar-analyze-count">{critiqueCount}</span>}
|
||||
</button>
|
||||
<div className="context-menu-separator" />
|
||||
<button
|
||||
className="context-menu-item"
|
||||
onClick={() => { setAnalyzeOpen(false); void runGrammar() }}
|
||||
>
|
||||
<span>Grammar</span>
|
||||
{grammarCount > 0 && <span className="toolbar-analyze-count">{grammarCount}</span>}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})(),
|
||||
|
||||
Reference in New Issue
Block a user