Skip to content

Conversation

knguyen1
Copy link
Contributor

@knguyen1 knguyen1 commented Oct 2, 2025

Summary

  • This is a…
    • Bug fix
    • Feature addition
    • Refactoring
    • Minor / simple change (like a typo)
    • Other
  • Describe this change in 1-2 sentences: Enhanced script autocompletion with dynamic variable parsing, plugin variable support, and context-aware completion for improved user experience.

Problem

The current script autocompletion system has several limitations:

  • Missing custom variables: When users create variables with $set(), those variables don't appear in autocompletion
  • No dynamic discovery: The system doesn't learn from existing scripts or current script content
  • Limited context awareness: No smart suggestions based on what the user is currently working on
  • No plugin extensibility: Plugins cannot register additional variables for completion

Solution

Implemented three major enhancements to the script completion system:

1. Dynamic Script Parsing

  • Real-time parsing of currently edited script to extract $set(variable_name, ...) calls
  • Uses existing ScriptParser for safe parsing with AST traversal
  • Caches parsed variables and updates on script changes
  • Includes regex fallback for resilience during live edits

2. Plugin Variable Extension

  • New extension point ext_point_script_variables for plugins to register variables
  • register_script_variable(name, documentation) function for plugin integration
  • Plugin variables appear in completion with %variable_name% format
  • Full integration with existing completion ranking and sorting

3. Context-Aware Completion

  • Smart completion based on cursor position and context
  • Function parameter completion: Shows tag names when cursor is inside $set(, $get(, etc.
  • Variable usage completion: Shows relevant variables when typing %
  • Smart filtering: Prioritizes recently used or contextually relevant variables
  • Handles complex nested structures and edge cases

Technical Implementation:

  • Extended ScriptCompleter with dynamic variable extraction methods
  • Added comprehensive test coverage for all new functionality
  • Maintains backward compatibility with existing completion behavior
  • Follows established extension point patterns used throughout Picard

Action

Additional actions required:

  • Update Picard documentation (please include a reference to this PR)
  • Other (please specify below)

…xtraction

- Introduced methods for extracting user-defined variables from scripts, including full parse, line parse, and regex fallback.
- Updated ScriptCompleter to maintain a cache of user-defined variables and dynamically update based on script content changes.
- Added comprehensive unit tests for variable extraction methods, covering various edge cases and error handling.
- Created new test files for regex fallback and AST parsing to ensure robust testing of the new features.
…pleter

- Added CompletionMode enum to manage different completion contexts.
- Enhanced ScriptCompleter to track variable usage and context for smarter suggestions.
- Implemented methods to detect function name and variable contexts, improving completion accuracy.
- Updated completion logic to handle tag name arguments for specific functions.
- Refined popup display logic to ensure relevant suggestions based on current context.
…l functions

- Introduced a new module for managing script variables in plugins.
- Implemented `register_script_variable` to allow plugins to register custom variables.
- Added `get_plugin_variable_names` and `get_plugin_variable_documentation` for retrieving registered variables and their documentation.
- Updated `ScriptCompleter` to include plugin variables in completion suggestions, enhancing user experience.
…pdates

- Updated error handling in ScriptCompleter to specifically catch RuntimeError during model updates, improving robustness.
- Adjusted tests to reflect the change in exception handling, ensuring graceful handling of model errors without raising exceptions.
…riable extraction

- Introduced VariableExtractor class to streamline the extraction of user-defined variables from script content using multiple strategies: full parsing, line-by-line parsing, and regex fallback.
- Updated ScriptCompleter to utilize VariableExtractor for variable collection, improving code organization and maintainability.
- Refactored existing variable extraction methods to leverage the new class, ensuring consistent behavior across different parsing strategies.
- Enhanced unit tests to cover the new extraction methods and validate their functionality against various edge cases.
… tests

- Introduced a new conftest.py file containing shared pytest fixtures to streamline testing across script_text_edit.
- Implemented a fixture to provide a minimal configuration for the script parser, enhancing test reliability and reducing code duplication.
… variable extraction for script completion

- Added ContextDetector class to identify completion contexts (function names, variables, tag name arguments) based on cursor position.
- Implemented VariableExtractor class to extract user-defined variables from script content using multiple strategies: full parsing, line-by-line parsing, and regex fallback.
- Updated ScriptTextEdit to utilize ContextDetector for smarter completion suggestions, enhancing user experience and accuracy.
- Refactored existing completion logic to streamline context detection and variable extraction processes.
…iableExtractor

- Introduced unit tests for the ContextDetector class, covering various context detection scenarios including function names, variables, and tag name arguments.
- Added tests for the VariableExtractor class to validate extraction of user-defined variables from script content using multiple strategies.
- Enhanced test coverage to include edge cases, error handling, and performance considerations for both classes.
- Implemented fixtures for streamlined test setup, improving maintainability and readability of test code.
…arguments

- Enhanced the ContextDetector class to prevent invalid syntax cases, specifically disallowing double parentheses immediately following function names.
- Updated unit tests to reflect this change, ensuring that invalid cases now return False as expected, improving the accuracy of context detection.
Copy link
Contributor

@Sophist-UK Sophist-UK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting so much effort in coding the tests cf. coding the solution.

…raction

- Introduced a pre-compiled regex pattern for variable extraction to enhance performance in the VariableExtractor class.
- Updated the _collect_from_regex method to utilize the new pattern, improving efficiency.
- Adjusted unit tests to reference the pre-compiled regex, ensuring consistency and maintainability.
…ompiled regex patterns

- Introduced pre-compiled regex patterns for counting variable usages in script content, improving performance and readability.
- Updated the _count_variable_usage method to utilize the new patterns, consolidating the logic for counting both %variable% and $get(variable) syntax.
- Enhanced maintainability by reducing redundancy in regex definitions.
…iptCompleter

- Consolidated variable suggestion logic by creating a unified list of all variables, sorted by usage count and name.
- Simplified the completion process for different modes, ensuring consistent handling of variable suggestions across contexts.
- Improved readability and maintainability of the choices method in ScriptCompleter.
…lugin_variable_names

- Streamlined the get_plugin_variable_names function by using a set comprehension for improved readability and performance.
- Removed unnecessary variable initialization and iteration, enhancing code efficiency while maintaining functionality.
…introduce regex patterns

- Implemented a new function to validate plugin variable names, ensuring they conform to specified patterns.
- Introduced a new module for regex patterns related to variable syntax, enhancing the robustness of variable name handling.
- Added comprehensive unit tests to verify the correctness of variable name validation, covering a wide range of valid and invalid cases.
…r script completion

- Added a new CompletionChoicesProvider class to generate completion choices based on context, user-defined variables, and usage counts.
- Implemented logic to sort and format completion choices for different modes, enhancing the script completion experience.
- Updated ScriptCompleter to utilize the new provider, streamlining the completion process and improving maintainability.
- Enhanced ContextDetector to support detailed context detection for tag name arguments, integrating with the new completion provider.
…er and ContextDetector

- Introduced unit tests for the CompletionChoicesProvider class, covering various scenarios including initialization, ordering, and deduplication of completion choices.
- Added tests for the ContextDetector class, validating its ability to detect context details for function calls and handle edge cases.
- Enhanced test coverage to include error handling and integration tests, ensuring robustness and reliability of the completion and context detection features.
- Implemented fixtures for streamlined test setup, improving maintainability and readability of test code.
…ance choice iteration

- Removed the default logic for yielding function names in the ScriptCompleter, streamlining the completion process.
- Updated the mock_choices_provider to return a fresh list instead of an iterator, preventing consumption issues during tests.
- Added a new test to ensure that function names are not duplicated in completion choices, improving the reliability of the completion feature.
…evel

- Move hardcoded 120ms value to _TEXT_CHANGE_DEBOUNCE_MS constant
- Add documentation explaining the timing choice (responsiveness vs performance)
…elper methods

- Improved the handle_autocomplete method to better manage autocomplete triggers and context updates.
- Introduced helper methods for checking force completion requests and updating completion context.
- Streamlined the process of showing the completion popup based on the current context, enhancing user experience and suggestion accuracy.
…CompletionChoicesProvider

- Updated the logic for collecting user-defined variables to directly include them in the all_variables list, removing unnecessary filtering.
- Enhanced readability and maintainability of the code by streamlining the variable aggregation process.
- Introduced UserScriptScanner to scan user tagging scripts for variable definitions, improving the autocompletion feature.
- Updated CompletionChoicesProvider to utilize the user script scanner, allowing user-defined variables from scripts to be included in completion choices.
- Enhanced ScriptCompleter to initialize with the user script scanner, ensuring user scripts are considered during completion.
- Added unit tests for both CompletionChoicesProvider and UserScriptScanner to validate functionality and integration, ensuring robust handling of user-defined variables.
… separate method

- Introduced a new method _calculate_scripts_hash to encapsulate the logic for calculating the hash of user scripts, improving code readability and maintainability.
- Updated scan_all_user_scripts and another relevant method to utilize the new hash calculation method, streamlining the scanning process.
… persistence

- Introduced methods to ensure the first item in the completion popup is consistently highlighted, improving user experience during autocompletion.
- Connected model signals to maintain the first-row selection after updates, addressing issues where the highlight could disappear due to asynchronous model changes.
- Added comprehensive unit tests to validate the new behavior, ensuring that the selection persists across various model updates and changes.
- Simplified the connection of model signals to the completion model update handler, enhancing code clarity and maintainability.
- Removed unnecessary lambda functions, directly connecting signals to the handler for improved performance and readability.
@zas zas requested review from phw and rdswift October 4, 2025 19:56
@rdswift
Copy link
Collaborator

rdswift commented Oct 4, 2025

Will it properly interpret cases where the variable name is passed indirectly to the $set() command? For example:

$noop( Create a separate tag for each artist listed for the
       track as 'artist_1', 'artist_2', etc. )
$foreach(%artists%,$set(artist_%_loop_count%,%_loop_value%))

Will this include the resulting artist_1, artist_2, etc. variables in the autocomplete list?

@rdswift
Copy link
Collaborator

rdswift commented Oct 4, 2025

Something for future consideration is to allow translated description strings for variables added (registered) by a plugin. I suppose that could be handled within the new plugin system, so the translated description is passed when registering the variable.

@knguyen1
Copy link
Contributor Author

knguyen1 commented Oct 5, 2025

Will this include the resulting artist_1, artist_2, etc. variables in the autocomplete list?

Out of scope of original JIRA requirement. Current AST parsing + regex fallback only covers statically named variables.

If you'd like me to proceed with dynamic var's, have to vote on it. I think it can be done with variable_extractor.py changes.

EDIT: Way too complex to solve--I will not be doing it. Besides, I think your example $foreach(%artists%,$set(artist_%_loop_count%,%_loop_value%)) relies on runtime context (the %artists% value) that the script parser does not have at time of parsing. One can probably write a parser for known formats like $foreach(1;2;3,$set(test_%_loop_count%,%_loop_value%)) though.

zas
zas previously approved these changes Oct 5, 2025
Copy link
Collaborator

@zas zas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Tested, work as expected for me.

Copy link
Member

@phw phw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really great addition. Both auto completion of user defined or plugin defined variables, but also the great idea of triggering variable automcompletion for functions like $set etc.

Only found one bug in the UI that I'd like to see resolved before merging: Once any input results in a parsing error and the red error bar is being shown, the error bar is not hidden again once the error is resolved.

@phw
Copy link
Member

phw commented Oct 10, 2025

EDIT: Way too complex to solve--I will not be doing it. Besides, I think your example $foreach(%artists%,$set(artist_%_loop_count%,%_loop_value%)) relies on runtime context (the %artists% value) that the script parser does not have at time of parsing. One can probably write a parser for known formats like $foreach(1;2;3,$set(test_%_loop_count%,%_loop_value%)) though.

Agreed that this is too complex to solve, and won't capture any case that requires context. Let's focus on statically declared variable names.

…d improve imports

- Replaced function-based regex pattern definitions with pre-compiled regex constants for better performance and clarity.
- Updated imports across multiple modules to utilize the new regex constants, enhancing code maintainability.
- Adjusted related tests to ensure compatibility with the new pattern definitions, improving overall test coverage and reliability.
- Added a debounce mechanism to improve user experience during script validation, reducing error flashing while typing.
- Introduced methods to handle text changes and process validation after a delay, ensuring timely feedback without interruptions.
- Updated error handling to ensure the error display is only shown when necessary, enhancing clarity for users.
@knguyen1
Copy link
Contributor Author

@phw That's out of scope of this PR's changes; it touches the file picard/ui/options/scripting.py. Regardless here is the change needed: fix(scripting_options): bug red error bar + add debounce

Also, I found it strange that the red error bar is unforgiving against pauses in typing. So added a debounce of 350ms.

Copy link
Member

@phw phw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes, and good idea with the debouncing. Just tested, works great.

@phw
Copy link
Member

phw commented Oct 10, 2025

That's out of scope of this PR's changes; it touches the file picard/ui/options/scripting.py. Regardless here is the change needed: fix(scripting_options): bug red error bar + add debounce

You are actually right, same issue is on master branch. So that's a regression on master already (works fine in the 2.x versions). I had assumed it would be broken in this branch only. But good to have it fixed regardless.

@phw phw merged commit 99f910c into metabrainz:master Oct 10, 2025
45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants