48 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			48 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as React from "react";
 | 
						|
import { WorkerParseError } from "../../languages/worker-errors";
 | 
						|
import {
 | 
						|
  createValidationMarker,
 | 
						|
  EditorInstance,
 | 
						|
  MonacoInstance,
 | 
						|
} from "./monaco-utils";
 | 
						|
 | 
						|
/** Constant denoting "owner" of syntax error markers */
 | 
						|
const MARKER_OWNER = "code-validation";
 | 
						|
 | 
						|
/** Delay between user's last edit and sending validation request */
 | 
						|
const VALIDATE_DELAY = 500;
 | 
						|
 | 
						|
type Args = {
 | 
						|
  editor: EditorInstance | null;
 | 
						|
  monaco: MonacoInstance | null;
 | 
						|
  onValidateCode: (code: string) => Promise<WorkerParseError | undefined>;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * React hook that sets up code validation lifecycle on the Monaco editor.
 | 
						|
 * Code validation is done a fixed delay after user's last edit, and markers
 | 
						|
 * for indicating syntax error are added to the editor.
 | 
						|
 */
 | 
						|
export const useCodeValidator = ({ editor, monaco, onValidateCode }: Args) => {
 | 
						|
  const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
 | 
						|
 | 
						|
  const runValidator = async () => {
 | 
						|
    if (!editor || !monaco) return;
 | 
						|
    const error = await onValidateCode(editor.getValue());
 | 
						|
    if (error)
 | 
						|
      monaco.editor.setModelMarkers(editor.getModel()!, MARKER_OWNER, [
 | 
						|
        createValidationMarker(monaco, error, error.range),
 | 
						|
      ]);
 | 
						|
  };
 | 
						|
 | 
						|
  React.useEffect(() => {
 | 
						|
    if (!editor || !monaco) return;
 | 
						|
    const disposer = editor.getModel()!.onDidChangeContent(() => {
 | 
						|
      monaco.editor.setModelMarkers(editor.getModel()!, MARKER_OWNER, []);
 | 
						|
      if (timeoutRef.current) clearTimeout(timeoutRef.current);
 | 
						|
      timeoutRef.current = setTimeout(runValidator, VALIDATE_DELAY);
 | 
						|
    });
 | 
						|
    return () => disposer.dispose();
 | 
						|
  }, [editor, monaco]);
 | 
						|
};
 |