declare let require ; const { math_escape , math_unescape } = require ( "@cocalc/util/markdown-utils" ) ; import { latex_format } from "./latex-format" ; import { python_format } from "./python-format" ; import { html_format } from "./html-format" ; import { xml_format } from "./xml-format" ; import { bib_format } from "./bib-format" ; import { r_format } from "./r-format" ; import genericFormat from "./generic-format" ; import { clang_format } from "./clang-format" ; import { gofmt } from "./gofmt" ; import { rust_format } from "./rust-format" ; const misc = require ( "@cocalc/util/misc" ) ; const { make_patch } = require ( "@cocalc/sync/editor/generic/util" ) ; const { remove_math , replace_math } = require ( "@cocalc/util/mathjax-utils" ) ; import { get_prettier } from "./prettier-lib" ; import { once } from "@cocalc/util/async-utils" ; import { Syntax as FormatterSyntax } from "@cocalc/util/code-formatter" ; export interface Config { syntax : FormatterSyntax ; tabWidth ? : number ; useTabs ? : boolean ; } export interface Options extends Omit < Config , "syntax" > { parser : FormatterSyntax ; tabWidth ? : number ; } export async function run_formatter ( client , path , options , logger ) { const syncstring = client . syncdoc ( { path } ) ; if ( syncstring == null || syncstring . get_state ( ) == "closed" ) { return { status : "error" , error : "document not fully opened" , phase : "format" , } ; } if ( syncstring . get_state ( ) != "ready" ) { await once ( syncstring , "ready" ) ; } const doc = syncstring . get_doc ( ) ; let formatted , math , input0 ; let input = ( input0 = doc . to_str ( ) ) ; if ( options . parser === "markdown" ) { [ input , math ] = remove_math ( math_escape ( input ) ) ; } try { formatted = await run_formatter_string ( path , input , options , logger ) ; } catch ( err ) { logger . debug ( `run_formatter error: ${ err . message }` ) ; return { status : "error" , phase : "format" , error : err . message } ; } if ( options . parser === "markdown" ) { formatted = math_unescape ( replace_math ( formatted , math ) ) ; } const patch = make_patch ( input0 , formatted ) ; return { status : "ok" , patch } ; } export async function run_formatter_string ( path , input , options , logger ) { let formatted ; logger . debug ( `run_formatter options.parser: "${ options . parser }"` ) ; switch ( options . parser ) { case "latex" : case "latexindent" : formatted = await latex_format ( input , options ) ; break ; case "python" : case "yapf" : formatted = await python_format ( input , options , logger ) ; break ; case "zig" : formatted = await genericFormat ( { command : "zig" , args : ( tmp ) => [ "fmt" , tmp ] , input , timeout_s : 30 , } ) ; break ; case "r" : case "formatR" : formatted = await r_format ( input , options , logger ) ; break ; case "html-tidy" : formatted = await html_format ( input , options , logger ) ; break ; case "xml-tidy" : formatted = await xml_format ( input , options , logger ) ; break ; case "bib-biber" : formatted = await bib_format ( input , options , logger ) ; break ; case "clang-format" : const ext = misc . filename_extension ( path != null ? path : "" ) ; formatted = await clang_format ( input , ext , options , logger ) ; break ; case "gofmt" : formatted = await gofmt ( input , options , logger ) ; break ; case "rust" : case "rustfmt" : formatted = await rust_format ( input , options , logger ) ; break ; default : const prettier = get_prettier ( ) ; if ( prettier != null ) { formatted = prettier . format ( input , options ) ; } else { throw Error ( "Could not load 'prettier'" ) ; } } return formatted ; }