@@ -219,77 +219,86 @@ def __init__(
219219
220220 def lex_document (self , document : Document ) -> Callable [[int ], Any ]:
221221 """Lex the document."""
222+ # Get redirection tokens and terminators to avoid highlighting them as values
223+ exclude_tokens = set (constants .REDIRECTION_TOKENS )
224+ exclude_tokens .update (self .cmd_app .statement_parser .terminators )
225+ arg_pattern = re .compile (r'(\s+)|(--?[^\s\'"]+)|("[^"]*"?|\'[^\']*\'?)|([^\s\'"]+)' )
226+
227+ def highlight_args (text : str , tokens : list [tuple [str , str ]]) -> None :
228+ """Highlight arguments in a string."""
229+ for m in arg_pattern .finditer (text ):
230+ space , flag , quoted , word = m .groups ()
231+ match_text = m .group (0 )
232+
233+ if space :
234+ tokens .append (('' , match_text ))
235+ elif flag :
236+ tokens .append ((self .flag_color , match_text ))
237+ elif (quoted or word ) and match_text not in exclude_tokens :
238+ tokens .append ((self .argument_color , match_text ))
239+ else :
240+ tokens .append (('' , match_text ))
222241
223242 def get_line (lineno : int ) -> list [tuple [str , str ]]:
224243 """Return the tokens for the given line number."""
225244 line = document .lines [lineno ]
226245 tokens : list [tuple [str , str ]] = []
227246
228- # Use cmd2's command pattern to find the first word (the command)
229- if ru .ALLOW_STYLE != ru .AllowStyle .NEVER and (
230- match := self .cmd_app .statement_parser ._command_pattern .search (line )
231- ):
232- # Group 1 is the command, Group 2 is the character(s) that terminated the command match
233- command = match .group (1 )
234- cmd_start = match .start (1 )
235- cmd_end = match .end (1 )
236-
237- # Add any leading whitespace
238- if cmd_start > 0 :
239- tokens .append (('' , line [:cmd_start ]))
240-
241- if command :
242- # Determine the style for the command
243- shortcut_found = False
244- for shortcut , _ in self .cmd_app .statement_parser .shortcuts :
245- if command .startswith (shortcut ):
246- # Add the shortcut with the command style
247- tokens .append ((self .command_color , shortcut ))
248-
249- # If there's more in the command word, it's an argument
250- if len (command ) > len (shortcut ):
251- tokens .append ((self .argument_color , command [len (shortcut ) :]))
252-
253- shortcut_found = True
254- break
255-
256- if not shortcut_found :
257- style = ''
258- if command in self .cmd_app .get_all_commands ():
259- style = self .command_color
260- elif command in self .cmd_app .aliases :
261- style = self .alias_color
262- elif command in self .cmd_app .macros :
263- style = self .macro_color
264-
265- # Add the command with the determined style
266- tokens .append ((style , command ))
267-
268- # Add the rest of the line
269- if cmd_end < len (line ):
270- rest = line [cmd_end :]
271- # Regex to match whitespace, flags, quoted strings, or other words
272- arg_pattern = re .compile (r'(\s+)|(--?[^\s\'"]+)|("[^"]*"?|\'[^\']*\'?)|([^\s\'"]+)' )
273-
274- # Get redirection tokens and terminators to avoid highlighting them as values
275- exclude_tokens = set (constants .REDIRECTION_TOKENS )
276- exclude_tokens .update (self .cmd_app .statement_parser .terminators )
277-
278- for m in arg_pattern .finditer (rest ):
279- space , flag , quoted , word = m .groups ()
280- text = m .group (0 )
281-
282- if space :
283- tokens .append (('' , text ))
284- elif flag :
285- tokens .append ((self .flag_color , text ))
286- elif (quoted or word ) and text not in exclude_tokens :
287- tokens .append ((self .argument_color , text ))
288- else :
289- tokens .append (('' , text ))
290- elif line :
291- # No command match found or colors aren't allowed, add the entire line unstyled
247+ # No syntax highlighting if styles are disallowed
248+ if ru .ALLOW_STYLE == ru .AllowStyle .NEVER :
292249 tokens .append (('' , line ))
250+ return tokens
251+
252+ # Only attempt to match a command on the first line
253+ if lineno == 0 :
254+ # Use cmd2's command pattern to find the first word (the command)
255+ match = self .cmd_app .statement_parser ._command_pattern .search (line )
256+ if match :
257+ # Group 1 is the command, Group 2 is the character(s) that terminated the command match
258+ command = match .group (1 )
259+ cmd_start = match .start (1 )
260+ cmd_end = match .end (1 )
261+
262+ # Add any leading whitespace
263+ if cmd_start > 0 :
264+ tokens .append (('' , line [:cmd_start ]))
265+
266+ if command :
267+ # Determine the style for the command
268+ shortcut_found = False
269+ for shortcut , _ in self .cmd_app .statement_parser .shortcuts :
270+ if command .startswith (shortcut ):
271+ # Add the shortcut with the command style
272+ tokens .append ((self .command_color , shortcut ))
273+
274+ # If there's more in the command word, it's an argument
275+ if len (command ) > len (shortcut ):
276+ tokens .append ((self .argument_color , command [len (shortcut ) :]))
277+
278+ shortcut_found = True
279+ break
280+
281+ if not shortcut_found :
282+ style = ''
283+ if command in self .cmd_app .get_all_commands ():
284+ style = self .command_color
285+ elif command in self .cmd_app .aliases :
286+ style = self .alias_color
287+ elif command in self .cmd_app .macros :
288+ style = self .macro_color
289+
290+ # Add the command with the determined style
291+ tokens .append ((style , command ))
292+
293+ # Add the rest of the line as arguments
294+ if cmd_end < len (line ):
295+ highlight_args (line [cmd_end :], tokens )
296+ else :
297+ # No command match found on the first line
298+ tokens .append (('' , line ))
299+ else :
300+ # All other lines are treated as arguments
301+ highlight_args (line , tokens )
293302
294303 return tokens
295304
0 commit comments