diff --git a/package.json b/package.json index fc5736b2d..91c07656f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "description": "If something is selected, only format the selection" }, "superbol.path": { - "default": "", + "default": "superbol-free", "description": "Path to the `superbol` command" } } @@ -74,6 +74,74 @@ ] } ], + "problemMatchers": [ + { + "name": "gnucobol", + "owner": "cobol", + "fileLocation": "absolute", + "pattern": "$gnucobol", + "source": "GnuCOBOL" + }, + { + "name": "gnucobol-warning", + "owner": "cobol", + "fileLocation": "absolute", + "pattern": "$gnucobol-warning", + "source": "GnuCOBOL", + "severity": "warning" + }, + { + "name": "gnucobol-error", + "owner": "cobol", + "fileLocation": "absolute", + "pattern": "$gnucobol-error", + "source": "GnuCOBOL", + "severity": "error" + }, + { + "name": "gnucobol-note", + "owner": "cobol", + "fileLocation": "absolute", + "pattern": "$gnucobol-note", + "source": "GnuCOBOL", + "severity": "info" + } + ], + "problemPatterns": [ + { + "name": "gnucobol", + "regexp": "^(.*): ?(\\d+): (error|warning): ([^[]*)(\\[(.*)\\])?$", + "file": 1, + "line": 2, + "severity": 3, + "code": 6, + "message": 4 + }, + { + "name": "gnucobol-warning", + "regexp": "^(.*):(\\d+):\\s?(warning|Warnung|[wW]aarschuwing|[aA]lerta|avertissement|упозорење)\\s?:([^[]*)(\\[(.*)\\])?$", + "file": 1, + "line": 2, + "code": 6, + "message": 4 + }, + { + "name": "gnucobol-error", + "regexp": "^(.*): ?(\\d+):\\s?(error|Fehler|[fF]out|[eE]rrores|[eE]rrores|erreur|грешка)\\s?:\\s?([^[]*)(\\[(.*)\\])?$", + "file": 1, + "line": 2, + "code": 6, + "message": 4 + }, + { + "name": "gnucobol-note", + "regexp": "^(.*): ?(\\d+): (note|Anmerkung|[nN]ota): ([^[]*)(\\[(.*)\\])?$", + "file": 1, + "line": 2, + "code": 6, + "message": 4 + } + ], "taskDefinitions": [ { "type": "superbol", @@ -83,7 +151,32 @@ "description": "The list of copybooks paths" }, "sourceFormat": { - "description": "The source format of the code" + "description": "The source format of the code", + "items": "string", + "enum": [ + "default", + "gnucobol", + "cobol85", + "cobol2002", + "cobol2014", + "acu", + "acu-strict", + "bs2000", + "bs2000-strict", + "gcos", + "gcos-strict", + "ibm", + "ibm-strict", + "mf", + "mf-strict", + "mvs", + "mvs-strict", + "realia", + "realia-strict", + "rm", + "rm-strict", + "xopen" + ] }, "dialect": { "description": "The COBOL dialect used" diff --git a/src/lsp/cobol_indent/cobol_indent.ml b/src/lsp/cobol_indent/cobol_indent.ml index ad15b12d0..716186b31 100644 --- a/src/lsp/cobol_indent/cobol_indent.ml +++ b/src/lsp/cobol_indent/cobol_indent.ml @@ -14,14 +14,12 @@ module Type = Indent_type (*return the result of indentation. use user-defined indent_config*) -let indent_range' = Indenter.indent_range' +let indent_range = Indenter.indent_range (*indent the whole file and print*) let indent_file ~dialect ~source_format ~file ~indent_config = - indent_range' ~dialect ~source_format ~range:None ~indent_config ~file - |> Fmt.pr "%s" - -(*indent a range of file and print*) -let indent_range ~dialect ~source_format ~file ~range ~indent_config = - indent_range' ~dialect ~source_format ~range ~indent_config ~file - |> Fmt.pr "%s" + let contents = Ez_file.V1.EzFile.read_file file in + indent_range + ~dialect ~source_format ~range:None ~indent_config + ~filename:file ~contents + |> Fmt.pr "%s" \ No newline at end of file diff --git a/src/lsp/cobol_indent/indent_type.ml b/src/lsp/cobol_indent/indent_type.ml index 897c42eb3..87d22439b 100644 --- a/src/lsp/cobol_indent/indent_type.ml +++ b/src/lsp/cobol_indent/indent_type.ml @@ -154,6 +154,7 @@ type context = (context_kind * int) list type indent_state = { + src_format: Cobol_preproc.Src_format.any; scope: context_kind; (*indicate where the current code is*) context: context; (*the stack of (context_kind, offset)*) acc: indent_record list; diff --git a/src/lsp/cobol_indent/indenter.ml b/src/lsp/cobol_indent/indenter.ml index 135129811..2d00f8005 100644 --- a/src/lsp/cobol_indent/indenter.ml +++ b/src/lsp/cobol_indent/indenter.ml @@ -27,14 +27,21 @@ let indenter ~source_format (str:string) (rdl:indent_record list) range = let str = List.nth strl (lnum - 1) in let newstr = match source_format with - | Cobol_config.SF SFFree -> + | Cobol_preproc.Src_format.SF (NoIndic, FreePaging) -> if offset > 0 then let space = String.make offset ' ' in space^str else String.sub str (-offset) (String.length str + offset) - (*TODO: must change if Auto <> SF SFFixed once*) - | SF SFFixed | Auto -> + | SF (FixedIndic, FixedWidth _) -> + (* Indenting temporarily disabled in fixed format + https://github.com/OCamlPro/superbol-studio-oss/issues/52 + + Support must be improved before enabling again, in particular to + avoid pushing content into the margin. + https://github.com/OCamlPro/superbol-studio-oss/issues/45 + *) + if true then str else let len = String.length str in let str1 = String.sub str 0 7 in let str = String.sub str 7 (len-7) in @@ -46,8 +53,11 @@ let indenter ~source_format (str:string) (rdl:indent_record list) range = String.sub str (-offset) (String.length str + offset) in str1^str - (*TODO*) - | _ -> str + (* TODO *) + | SF (XOpenIndic, FixedWidth _) -> str + | SF (CRTIndic, FixedWidth _) -> str + | SF (TrmIndic, FixedWidth _) -> str + | SF (CBLXIndic, FixedWidth _) -> str in List.mapi (fun i str -> if i = lnum - 1 then newstr else str) (strl) in @@ -62,30 +72,33 @@ let indenter ~source_format (str:string) (rdl:indent_record list) range = String.concat "\n" strl (*indent a range of file, with the default indent_config*) -let indent_range' ~dialect ~source_format ~range ~file = - let file_content = Ez_file.V1.EzFile.read_file file in - (* - Not satisfied with the `Cobol_preproc.fold_text_lines`, - this function has an argument which is the name of file, - so when using lsp, every time using the formatting, - we must save the file before, it is not convenient. - (* NB: not anymore. *) - *) +let indent_range ~dialect ~source_format ~range ~filename ~contents = + (* Note: this value doesn't actually matter, it will be overriden + immediately by [fold_source_lines] calling [on_initial_source_format] + below. *) + let src_format = Cobol_preproc.Src_format.from_config SFFixed in let state = Cobol_preproc.fold_source_lines ~dialect ~source_format - ~skip_compiler_directives_text:false + ~on_initial_source_format:(fun src_format st -> { st with src_format }) + ~on_compiler_directive:(fun _ { payload = cd; _} st -> + match cd with + | CDirSource { payload = src_format; _ } -> { st with src_format } + | _ -> st + ) + ~skip_compiler_directives_text:true ~f:(fun _lnum line acc -> Indent_check.check_indentation line acc) - (String { contents = file_content; filename = file; }) - { scope = BEGIN; context = []; acc = []; range } + (String { filename; contents }) + { src_format; scope = BEGIN; context = []; acc = []; range } in (* NB: note here we ignore diagnostics *) let ind_recds = state.result.acc in - indenter ~source_format file_content ind_recds state.result.range + indenter + ~source_format:state.result.src_format contents ind_recds state.result.range (*indent a range of file, with the user-defined indent_config*) -let indent_range' ~dialect ~source_format ~indent_config ~range ~file = +let indent_range ~dialect ~source_format ~indent_config ~range ~filename ~contents = begin match indent_config with | Some indent_config -> Indent_config.set_config ~indent_config | None -> () end; - indent_range' ~dialect ~source_format ~range ~file + indent_range ~dialect ~source_format ~range ~filename ~contents \ No newline at end of file diff --git a/src/lsp/cobol_indent/indenter.mli b/src/lsp/cobol_indent/indenter.mli index c6f62793e..05a0fbe70 100644 --- a/src/lsp/cobol_indent/indenter.mli +++ b/src/lsp/cobol_indent/indenter.mli @@ -12,10 +12,11 @@ (**************************************************************************) (*indent a range of file, with the user-defined or default indent_config*) -val indent_range' +val indent_range : dialect: Cobol_config.dialect -> source_format:Cobol_config.source_format_spec -> indent_config:string option -> range:Indent_type.range option - -> file:string + -> filename:string + -> contents:string -> string diff --git a/src/lsp/cobol_lsp/lsp_request.ml b/src/lsp/cobol_lsp/lsp_request.ml index f33e79d26..bf24ed764 100644 --- a/src/lsp/cobol_lsp/lsp_request.ml +++ b/src/lsp/cobol_lsp/lsp_request.ml @@ -159,7 +159,9 @@ let handle_references state (params: ReferenceParams.t) = let handle_range_formatting registry params = let open DocumentRangeFormattingParams in let { textDocument = doc; range = {start; end_}; _ } = params in - let Lsp_document.{ project; _ } = Lsp_server.find_document doc registry in + let Lsp_document.{ project; textdoc; _ } = + Lsp_server.find_document doc registry + in let range_to_indent = Cobol_indent.Type.{ start_line = start.line + 1; @@ -176,11 +178,12 @@ let handle_range_formatting registry params = } in let newText = - Cobol_indent.indent_range' + Cobol_indent.indent_range ~dialect:(Cobol_config.dialect project.config.cobol_config) ~source_format:project.config.source_format ~indent_config:None - ~file:(Lsp.Uri.to_path doc.uri) + ~filename:(Lsp.Uri.to_path doc.uri) + ~contents:(Lsp.Text_document.text textdoc) ~range:(Some range_to_indent) in Some [TextEdit.create ~newText ~range] @@ -198,14 +201,14 @@ let handle_formatting registry params = ~start:(Position.create ~character:0 ~line:0) ~end_:(Position.create ~character:width ~line:length) in - let path = Lsp.Uri.to_path doc.uri in try let newText = - Cobol_indent.indent_range' + Cobol_indent.indent_range ~dialect:(Cobol_config.dialect project.config.cobol_config) ~source_format:project.config.source_format ~indent_config:None - ~file:path + ~filename:(Lsp.Uri.to_path doc.uri) + ~contents:(Lsp.Text_document.text textdoc) ~range:None in Some [TextEdit.create ~newText ~range:edit_range] diff --git a/src/lsp/superbol_free_lib/command_indent_file.ml b/src/lsp/superbol_free_lib/command_indent_file.ml index e1b144835..0ee37040b 100644 --- a/src/lsp/superbol_free_lib/command_indent_file.ml +++ b/src/lsp/superbol_free_lib/command_indent_file.ml @@ -17,11 +17,15 @@ open Cobol_indent open Common_args -let action { preproc_options = { source_format; _ } ; _ } ~indent_config - files = +let action { preproc_options = { source_format; config; _ } ; _ } + ~indent_config files = + let module Config = (val config) in List.to_seq files |> Seq.map (fun file -> - indent_file ~source_format ~file ~indent_config) + let contents = Ez_file.V1.EzFile.read_file file in + indent_range + ~source_format ~filename:file ~contents ~indent_config ~range:None + ~dialect:Config.dialect |> Fmt.pr "%s") let cmd = let files = ref [] in diff --git a/src/lsp/superbol_free_lib/command_indent_range.ml b/src/lsp/superbol_free_lib/command_indent_range.ml index 7d3d86871..d41bed4ff 100644 --- a/src/lsp/superbol_free_lib/command_indent_range.ml +++ b/src/lsp/superbol_free_lib/command_indent_range.ml @@ -20,8 +20,9 @@ open Common_args let action { preproc_options = { source_format; config; _ }; _ } ~file ~range ~indent_config = let module Config = (val config) in - indent_range ~source_format ~file ~range ~indent_config - ~dialect:Config.dialect + let contents = Ez_file.V1.EzFile.read_file file in + indent_range ~source_format ~filename:file ~contents ~range ~indent_config + ~dialect:Config.dialect |> Fmt.pr "%s" let cmd = let file = ref "" in diff --git a/src/lsp/superbol_free_lib/project.ml b/src/lsp/superbol_free_lib/project.ml index e83a084ee..c28f79244 100644 --- a/src/lsp/superbol_free_lib/project.ml +++ b/src/lsp/superbol_free_lib/project.ml @@ -144,7 +144,7 @@ let contributes = "If something is selected, only format the selection" ; Manifest.PROPERTY.string "superbol.path" - ~default: "" + ~default:"superbol-free" ~description: "Path to the `superbol` command" ] ) ~taskDefinitions: [ @@ -154,8 +154,10 @@ let contributes = Manifest.PROPERTY.array "copybooks" ~description:"The list of copybooks paths" ; - Manifest.PROPERTY.string "sourceFormat" - ~description: "The source format of the code" ; + Manifest.PROPERTY.enum "sourceFormat" + ~cases:Cobol_config.DIALECT.all_canonical_names + ~description: "The source format of the code" + ; Manifest.PROPERTY.string "dialect" ~description: "The COBOL dialect used" ; @@ -167,6 +169,66 @@ let contributes = ~description: "Add cobol file extensions" ] ] + ~problemPatterns:[ + Manifest.problemPattern + (Some "^(.*): ?(\\d+): (error|warning): ([^[]*)(\\[(.*)\\])?$") + ~name:"gnucobol" + ~file:1 + ~line:2 + ~severity:3 + ~message:4 + ~code:6; + Manifest.problemPattern + (Some "^(.*):(\\d+):\\s?(warning|Warnung|[wW]aarschuwing|[aA]lerta|avertissement|упозорење)\\s?:([^[]*)(\\[(.*)\\])?$") + ~name:"gnucobol-warning" + ~file:1 + ~line:2 + ~message:4 + ~code:6; + Manifest.problemPattern + (Some "^(.*): ?(\\d+):\\s?(error|Fehler|[fF]out|[eE]rrores|[eE]rrores|erreur|грешка)\\s?:\\s?([^[]*)(\\[(.*)\\])?$") + ~name:"gnucobol-error" + ~file:1 + ~line:2 + ~message:4 + ~code:6; + Manifest.problemPattern + (Some "^(.*): ?(\\d+): (note|Anmerkung|[nN]ota): ([^[]*)(\\[(.*)\\])?$") + ~name:"gnucobol-note" + ~file:1 + ~line:2 + ~message:4 + ~code:6; + ] + ~problemMatchers:[ + Manifest.problemMatcher () + ~name:"gnucobol" + ~owner:"cobol" + ~fileLocation:["absolute"] + ~pattern:[Manifest.ProblemName "$gnucobol"] + ~source:"GnuCOBOL"; + Manifest.problemMatcher () + ~name:"gnucobol-warning" + ~owner:"cobol" + ~fileLocation:["absolute"] + ~pattern:[Manifest.ProblemName "$gnucobol-warning"] + ~severity:"warning" + ~source:"GnuCOBOL"; + Manifest.problemMatcher () + ~name:"gnucobol-error" + ~owner:"cobol" + ~fileLocation:["absolute"] + ~pattern:[Manifest.ProblemName "$gnucobol-error"] + ~severity:"error" + ~source:"GnuCOBOL"; + Manifest.problemMatcher () + ~name:"gnucobol-note" + ~owner:"cobol" + ~fileLocation:["absolute"] + ~pattern:[Manifest.ProblemName "$gnucobol-note"] + ~severity:"info" + ~source:"GnuCOBOL"; + ] let manifest = Manifest.vscode diff --git a/src/vscode/superbol-vscode-platform/superbol_tasks.ml b/src/vscode/superbol-vscode-platform/superbol_tasks.ml index 3ebd6dce4..58b9470e8 100644 --- a/src/vscode/superbol-vscode-platform/superbol_tasks.ml +++ b/src/vscode/superbol-vscode-platform/superbol_tasks.ml @@ -69,6 +69,12 @@ let provide_tasks ~token:_ = ~name:"Build file" ~source:"superbol" ~execution:(execution "cobc") + ~problemMatchers:[ + "$gnucobol"; + "$gnucobol-warning"; + "$gnucobol-error"; + "$gnucobol-note"; + ] in let build_debug_task = Task.make () ~definition:definition_debug @@ -76,6 +82,12 @@ let provide_tasks ~token:_ = ~name:"Build file for debug" ~source:"superbol" ~execution:(execution "cobcd") + ~problemMatchers:[ + "$gnucobol"; + "$gnucobol-warning"; + "$gnucobol-error"; + "$gnucobol-note"; + ] in `Value (Some [build_task; build_debug_task]) diff --git a/src/vscode/vscode-json/manifest.ml b/src/vscode/vscode-json/manifest.ml index 142d1dce3..1c88d601b 100644 --- a/src/vscode/vscode-json/manifest.ml +++ b/src/vscode/vscode-json/manifest.ml @@ -357,6 +357,13 @@ module PROPERTY = struct Some (`A (List.map (fun s -> `String s) strings))) ~items: (`String "string") + let enum ?default ~cases = + property + ~type_:(`String "string") + ~enum:cases + ?default + ~items:(`String "string") + end type configuration = { diff --git a/test/lsp/lsp_formatting.ml b/test/lsp/lsp_formatting.ml index ada273b8b..fcdf97df9 100644 --- a/test/lsp/lsp_formatting.ml +++ b/test/lsp/lsp_formatting.ml @@ -14,6 +14,12 @@ open Lsp.Types open Lsp_testing +let make_free_format_project () = + make_lsp_project () ~toml:{toml| + [cobol] + source-format = "free" + |toml} + let doc = {cobol| PROGRAM-ID. HELLO. PROCEDURE DIVISION. @@ -23,7 +29,7 @@ let doc = {cobol| |cobol};; let%expect_test "simple-formatting-request" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -57,7 +63,7 @@ let doc = {cobol| move 1 to x. |cobol};; let%expect_test "formatting-request-nested-if" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -98,7 +104,7 @@ let doc = {cobol| value 999. |cobol};; let%expect_test "formatting-request-data" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -170,7 +176,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-nested-program" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -227,7 +233,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-alignment-argument" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -258,7 +264,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-else-if" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -375,7 +381,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-whole-program" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -500,7 +506,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-on-exception" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in @@ -534,7 +540,7 @@ let doc = {cobol| |cobol};; let%expect_test "formatting-request-perform" = - let { projdir; end_with_postproc }, server = make_lsp_project () in + let { projdir; end_with_postproc }, server = make_free_format_project () in let server, prog = add_cobol_doc server ~projdir "prog.cob" doc in let params = let options = FormattingOptions.create ~insertSpaces:true ~tabSize:2 () in