diff --git a/client/src/common/settings.ts b/client/src/common/settings.ts index b10e7ca..c919394 100644 --- a/client/src/common/settings.ts +++ b/client/src/common/settings.ts @@ -78,7 +78,8 @@ export async function getWorkspaceSettings( path: resolveVariables(config.get(`path`) ?? [], workspace), interpreter: resolveVariables(interpreter, workspace), importStrategy: config.get(`importStrategy`) ?? "useBundled", - showNotifications: config.get(`showNotifications`) ?? "off" + showNotifications: config.get(`showNotifications`) ?? "off", + formatter: config.get(`formatter`) ?? true } return workspaceSetting } @@ -109,7 +110,8 @@ export async function getGlobalSettings( path: getGlobalValue(config, "path", []), interpreter: interpreter, importStrategy: getGlobalValue(config, "importStrategy", "useBundled"), - showNotifications: getGlobalValue(config, "showNotifications", "off") + showNotifications: getGlobalValue(config, "showNotifications", "off"), + formatter: config.get(`formatter`) ?? true } return setting } @@ -123,7 +125,8 @@ export function checkIfConfigurationChanged( `${namespace}.path`, `${namespace}.interpreter`, `${namespace}.importStrategy`, - `${namespace}.showNotifications` + `${namespace}.showNotifications`, + `${namespace}.formatter` ] const changed = settings.map((s) => e.affectsConfiguration(s)) return changed.includes(true) diff --git a/package.json b/package.json index 24fb9c7..2211175 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nx-post-support", "displayName": "NX Postprocessor Support", "description": "", - "version": "0.4.1", + "version": "0.4.6", "publisher": "Christoph", "serverInfo": { "name": "NX Postprocessor Support", @@ -79,6 +79,11 @@ ], "configuration": { "properties": { + "nx-post-support.formatter": { + "type": "boolean", + "default": false, + "description": "Use the TCL formatter from `NX Postprocessor Support`" + }, "nx-post-support.importStrategy": { "default": "useBundled", "description": "Defines where `NX Postprocessor Support` is imported from.", @@ -118,4 +123,4 @@ "prettier": "^3.4.2", "typescript": "^5.7.2" } -} +} \ No newline at end of file diff --git a/server/src/common/completion_list.json b/server/src/common/completion_list.json index 3bdb27c..b8aa7c1 100644 --- a/server/src/common/completion_list.json +++ b/server/src/common/completion_list.json @@ -4,6 +4,10 @@ "label": "proc", "kind": "keyword" }, + { + "label": "switch", + "kind": "keyword" + }, { "label": "if", "kind": "keyword" @@ -19,6 +23,10 @@ { "label": "puts", "kind": "function" + }, + { + "label": "set", + "kind": "keyword" } ], "MOM_procs": [ @@ -233,6 +241,72 @@ "set path [MOM_ask_env_var UGII_CAM_POST_CONFIG_FILE]" ] }, + { + "label": "MOM_ask_ess_exp_value", + "kind": "function", + "description": "This function provides access to the variables of the NX Expression module. The NX Expression module allows users to define variables and expressions to use as parameters for NX entities such as modeling features.", + "format": "MOM_ask_ess_exp_value ", + "parameters": [ + { + "name": "variable_name", + "desc": "Name of the NX Expression variable." + } + ], + "returns": [ + "Value of the NX Expression variable." + ], + "example": [ + "MOM_ask_ess_exp_value diameter" + ] + }, + { + "label": "MOM_ask_event_type", + "kind": "function", + "description": "This procedure returns the name of the current event. This is the last event that the event generator executed.", + "format": "MOM_ask_event_type", + "parameters": [], + "returns": [ + "Name of current event." + ], + "example": [ + "set event [MOM_ask_event_type]" + ] + }, + { + "label": "MOM_ask_group_info", + "kind": "function", + "description": "This command retrieves group information in a CAM setup from the operation navigator views for the specified operation or group name. Returns an integer value (-1, 0, or 1) and stores the result in the variables mom_result and mom_result1.", + "format": "MOM_ask_group_info ", + "parameters": [ + { + "name": "node_name", + "desc": "Operation or group name." + }, + { + "name": "view", + "desc": "View in the operation navigator (ONT). (program|prog, tool, geometry|geom, method|meth)" + }, + { + "name": "parent|children", + "desc": "Type of node." + } + ], + "returns": [ + "-1: Query failed, or the node does not exist.", + "0: Current node is root node, or no child node.", + "1: Get current group information." + ], + "example": [ + "MOM_ask_group_info UGT0361_019 tool children", + "mom_result(0) = CHAMFER_S1H_CSINK", + "mom_result(1) = CHAMFER_S1H_CSINK1", + "mom_result1(CHAMFER_S1H_CSINK) = Drilling", + "mom_result1(CHAMFER_S1H_CSINK1) = Drilling", + "MOM_ask_group_info CHAMFER_S1H_CSINK tool parent", + "mom_result = UGT0361_019", + "mom_result1 = Countersink" + ] + }, { "label": "MOM_ask_ude_info", "kind": "function", @@ -257,6 +331,25 @@ "1 - The UDE information successfully retrieved." ], "example": [] + }, + { + "label": "MOM_suppress", + "kind": "function", + "description": "The next time that a block template that contains a reference to any of the input address names is evaluated, the word that contains the address is not be output regardless of its modality attribute.", + "format": "MOM_suppress ", + "parameters": [ + { + "name": "Always|Once|Off", + "desc": "Always - Sets the address to be to be non-modal (always output).\nOnce - The next time that a block template that contains a reference to any of the input address names is evaluated, the word that contains that address is not output regardless of its modality attribute. If both MOM_force Once and MOM_suppress Once are programmed, the last one will take effect. If MOM_suppress Always is programmed, the address is never output. All MOM_force Once and MOM_suppress Once commands are ignored.\nff - Sets the address to be to be modal (output only if value changes)." + }, + { + "name": "address_1 ... address_n", + "desc": "Name of output address(es)." + } + ], + "example": [ + "MOM_suppress_address Always N X Y" + ] } ], "mom_variables": [ diff --git a/server/src/common/formatter.py b/server/src/common/formatter.py index ff9469b..29f72eb 100644 --- a/server/src/common/formatter.py +++ b/server/src/common/formatter.py @@ -15,43 +15,48 @@ def format_tcl(src: str, indent_str=" ") -> str: for raw_line in src.splitlines(): stripped = raw_line.strip() - # 1) Single-line 'if {cond} {action}' → no indent change + # Comments are ignored + if stripped.startswith("#"): + out_lines.append(indent_str * level + stripped) + continue + + # Single-line 'if {cond} {action}' → no indent change if re.match(r"^(if|elseif)\s*\{[^}]+\}\s*\{[^}]+\}$", stripped): out_lines.append(indent_str * level + stripped) continue - # 2) Combined '} else {' → dedent, print, then indent + # Combined '} else {' → dedent, print, then indent if re.match(r"^\}\s*(elseif|else)\b.*\{$", stripped): level = max(level - 1, 0) out_lines.append(indent_str * level + stripped) level += 1 continue - # 3) SPECIAL: closing brace plus tag on same line: '} Tag' - m = re.match(r"^\}\s+(\w+)$", stripped) - if m: + # SPECIAL: closing brace plus tag on same line: '} Tag' + m = re.match(r"^\}\s+(.+)", stripped) + if m and not stripped.startswith("#"): # close one block level = max(level - 1, 0) # stay on one line: "} Tag" out_lines.append(f"{indent_str * level}}} {m.group(1)}") continue - # 4) Pure '}' → dedent then print + # Pure '}' → dedent then print if stripped == "}": level = max(level - 1, 0) out_lines.append(f"{indent_str * level}{stripped}") continue - # 5) 'elseif' or 'else' alone → align with matching 'if' + # 'elseif' or 'else' alone → align with matching 'if' if re.match(r"^(elseif|else)\b(?!.*\{)", stripped): level = max(level - 1, 0) out_lines.append(f"{indent_str * level}{stripped}") continue - # 6) Default: print at current indent + # Default: print at current indent out_lines.append(f"{indent_str * level}{stripped}") - # 7) Open a new block on lines ending with '{' + # Open a new block on lines ending with '{' if re.match(r"^(if|elseif)\b.*\{$", stripped) or stripped.endswith("{"): level += 1 diff --git a/server/src/lsp_server.py b/server/src/lsp_server.py index f835f95..2d8ea86 100644 --- a/server/src/lsp_server.py +++ b/server/src/lsp_server.py @@ -55,9 +55,6 @@ LSP_SERVER = server.LanguageServer( name="NX Postprocessor Support", version="0.0.1", max_workers=MAX_WORKERS ) - -NX_PROC_LIST = [] - # ********************************************************** # Tool specific code goes below this. # ********************************************************** @@ -194,7 +191,9 @@ def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | Non doc = LSP_SERVER.workspace.get_text_document(params.text_document.uri) text = doc.source - formatted = format_tcl(text) + formatted = text + if GLOBAL_SETTINGS.get("formatter", False): + formatted = format_tcl(text) last_line = len(text.splitlines()) full_range = lsp.Range( @@ -208,6 +207,13 @@ def formatting(params: lsp.DocumentFormattingParams) -> list[lsp.TextEdit] | Non # ********************************************************** # Required Language Server Initialization and Exit handlers. # ********************************************************** +@LSP_SERVER.feature(lsp.WORKSPACE_DID_CHANGE_CONFIGURATION) +def did_change_configuration(params: lsp.DidChangeConfigurationParams): + settings = params.settings + + log_to_output(str(settings)) + + @LSP_SERVER.feature(lsp.INITIALIZE) def initialize(params: lsp.InitializeParams) -> lsp.InitializeResult: """LSP handler for initialize request.""" @@ -228,7 +234,7 @@ def initialize(params: lsp.InitializeParams) -> lsp.InitializeResult: ) return lsp.InitializeResult( capabilities=lsp.ServerCapabilities( - document_formatting_provider=True, + document_formatting_provider=GLOBAL_SETTINGS.get("formatter", True), ) ) @@ -252,6 +258,7 @@ def _get_global_defaults(): "args": GLOBAL_SETTINGS.get("args", []), "importStrategy": GLOBAL_SETTINGS.get("importStrategy", "useBundled"), "showNotifications": GLOBAL_SETTINGS.get("showNotifications", "off"), + "formatter": GLOBAL_SETTINGS.get("formatter", True), }