@@ -3,7 +3,6 @@ import { FunctionComponent, useEffect, useRef } from "react";
33import type { IDisposable } from "monaco-editor" ;
44import { vsPlusTheme } from "monaco-sql-languages" ;
55import EditorComponent , { useMonaco } from "@monaco-editor/react" ;
6- import { format as formatSql } from "sql-formatter" ;
76
87import {
98 COMMAND_CONFIG ,
@@ -15,6 +14,7 @@ import { fetchAutocomplete } from "@/api";
1514import { Card } from "@/components/ui/card" ;
1615import { useQuery } from "@tanstack/react-query" ;
1716import { useTheme } from "@/provider/theme.provider" ;
17+ import { useSqlFormattingProviders } from "@/lib/monaco" ;
1818
1919type Props = {
2020 value : string ;
@@ -25,7 +25,7 @@ export const Editor: FunctionComponent<Props> = ({ value, onChange }) => {
2525 const currentTheme = useTheme ( ) ;
2626 const monacoInstance = useMonaco ( ) ;
2727 const providerRef = useRef < IDisposable | null > ( null ) ;
28- const formatProviderRefs = useRef < IDisposable [ ] > ( [ ] ) ;
28+
2929
3030 const { data : autoCompleteData } = useQuery ( {
3131 queryKey : [ "autocomplete" ] ,
@@ -124,74 +124,10 @@ export const Editor: FunctionComponent<Props> = ({ value, onChange }) => {
124124 } , [ monacoInstance , autoCompleteData ] ) ;
125125
126126 // Register formatting providers (document and range)
127- useEffect ( ( ) => {
128- if ( ! monacoInstance ) return ;
129-
130- // Dispose previous providers if any
131- formatProviderRefs . current . forEach ( ( d ) => d . dispose ( ) ) ;
132- formatProviderRefs . current = [ ] ;
133-
134- const getOptions = ( ) => ( {
135- language : "sqlite" as const ,
136- keywordCase : "upper" as const ,
137- indent : " " ,
138- } ) ;
139-
140- const documentProvider =
141- monacoInstance . languages . registerDocumentFormattingEditProvider (
142- ID_LANGUAGE_SQL ,
143- {
144- provideDocumentFormattingEdits : ( model ) => {
145- const fullRange = model . getFullModelRange ( ) ;
146- const text = model . getValue ( ) ;
147- try {
148- const formatted = formatSql ( text , getOptions ( ) ) ;
149- return [
150- {
151- range : fullRange ,
152- text : formatted ,
153- } ,
154- ] ;
155- } catch ( err ) {
156- // Keep UX stable if formatting fails
157- // eslint-disable-next-line no-console
158- console . error ( "SQL formatting error (document)" , err ) ;
159- return [ ] ;
160- }
161- } ,
162- }
163- ) ;
164-
165- const rangeProvider =
166- monacoInstance . languages . registerDocumentRangeFormattingEditProvider (
167- ID_LANGUAGE_SQL ,
168- {
169- provideDocumentRangeFormattingEdits : ( model , range ) => {
170- const text = model . getValueInRange ( range ) ;
171- try {
172- const formatted = formatSql ( text , getOptions ( ) ) ;
173- return [
174- {
175- range,
176- text : formatted ,
177- } ,
178- ] ;
179- } catch ( err ) {
180- // eslint-disable-next-line no-console
181- console . error ( "SQL formatting error (range)" , err ) ;
182- return [ ] ;
183- }
184- } ,
185- }
186- ) ;
187-
188- formatProviderRefs . current = [ documentProvider , rangeProvider ] ;
189-
190- return ( ) => {
191- formatProviderRefs . current . forEach ( ( d ) => d . dispose ( ) ) ;
192- formatProviderRefs . current = [ ] ;
193- } ;
194- } , [ monacoInstance ] ) ;
127+ // Use centralized formatting providers
128+ // Moved into lib to keep this component lean
129+ useSqlFormattingProviders ( monacoInstance , { languageId : ID_LANGUAGE_SQL } ) ;
130+
195131
196132 // Avoid rendering until theme is known
197133 if ( ! currentTheme ) return null ;
0 commit comments