zero-plusplus / vscode-autohotkey-debug

https://marketplace.visualstudio.com/items?itemName=zero-plusplus.vscode-autohotkey-debug
MIT License
50 stars 4 forks source link

Category enhancements and disruptive changes #312

Open zero-plusplus opened 6 months ago

zero-plusplus commented 6 months ago

Currently, categories can display only built-in variables, or display variables of particular interest as a group, and so on.

I thought this could be viewed as a static watch expression.

Watch expressions essentially have to be set manually, and I have been frustrated by the fact that unwanted watch expressions persist.

My idea of a new feature for categories is that it would only show up under certain conditions and would show the specified expression.

For example, unit tests would have a specific naming convention (such as starting with test). Also, a parameter test may have a specific argument name, such as expected, actual, etc. In such a case, a unit test is used.

Only if you are unit testing in such a case, you can make it work as a static watch expression that monitors expected and actual.

This will only show up in situations where it is needed, and hide it otherwise.

Here I am trying to come up with an interface for the new category.

If you have any ideas or improvements, please write to me.


export type SourceName
  = 'Local'
  | 'Global'
  | 'Static'; // AutoHotkey_H only
export type SourceSelector = '*' | SourceName;
export type Expression = string;
export type VisibleCondition = boolean | Expression;
export interface VariableMatcher {
  pattern?: MatchPattern;
  attributes: VariableAttributes;
}
export type PatternLiteral
  = VariablePrefixPatternLiteral
  | VariableSuffixxPatternLiteral
  | VariableExactPatternLiteral
  | VariableRegExPatternLiteral
  | VariableWildcardPatternLiteral;
export type VariablePrefixPatternLiteral = `>${string}>`;
export type VariableSuffixxPatternLiteral = `<${string}<`;
export type VariableExactPatternLiteral = `>${string}<`;
export type VariableRegExPatternLiteral = `/${string}/`;
export type VariableWildcardPatternLiteral = `|${string}|` | string & { ThisIsLiteralUnionTrick: any };

export type MatchPattern
  = PatternLiteral
  | VariableRegExPattern
  | VariablePrefixPattern
  | VariableSuffixPattern
  | VariableExactPattern
  | VariableRegExPattern
  | VariableWildcardPattern;
export type PatternType = 'partial' | 'prefix' | 'suffix' | 'exact' | 'regex' | 'regexp' | 'wildcard';
export interface VariablePatternBase {
  patternType: PatternType;
  pattern: string;
  ignorecase?: boolean;
}
export interface VariablePartialPattern extends VariablePatternBase {
  patternType: 'partial';
}
export interface VariablePrefixPattern extends VariablePatternBase {
  patternType: 'prefix';
}
export interface VariableSuffixPattern extends VariablePatternBase {
  patternType: 'suffix';
}
export interface VariableExactPattern extends VariablePatternBase {
  patternType: 'exact';
}
export interface VariableRegExPattern extends VariablePatternBase {
  patternType: 'regex' | 'regexp';
}
export interface VariableWildcardPattern extends VariablePatternBase {
  patternType: 'wildcard';
}
export interface VariableAttributes {
  type?: string;
  kindName?: string;
  isBuiltin?: boolean;
  isStatic?: boolean;
}

export type DefinedCategoryName = SourceName | 'Builtin-Global' | 'UserDefined-Global';
export interface VariableCategory {
  label: string;
  items: CategoryItem[];
  visible?: VisibleCondition;
  filters?: DefinedCategoryName | VariableMatcher[];
}
export type CategoryItem
  = VariableCategoryItem
  | ExpressionCategoryItem
  | CategoryItemSelector;
export interface CategoryItemBase {
  visible: VisibleCondition;
}
export interface VariableCategoryItem extends CategoryItemBase {
  name: string;
  scope?: SourceName;
}
export interface ExpressionCategoryItem extends CategoryItemBase {
  label: string;
  expression?: Expression;
}
export interface CategoryItemSelector extends CategoryItemBase {
  source: SourceSelector | SourceName[];
  select?: PatternLiteral | VariableMatcher;
}

Previously, the process of selecting variables from the source and excluding unwanted variables from it was processed like a piped process in a functional language, where the process is represented by a single array.

Programmatically this was fine, but as a json string it was a rather strange specification. Therefore, I made the roles clear by creating separate arrays for the method of selecting variables from the source and for the method of excluding unwanted variables.

// The following is a comparison of the case where the values are set to have the same meaning as in `variableCategories: "recommanded"`
// New implementations
{
  ...
  "variableCategories": [
    {
      "label": "Local",
      "items": [
        {
          "source": "Local"
        }
      ]
    },
    {
      "label": "Global",
      "items": [
        {
          "source": "Global",
          "select": {
            "attributes": {
              "isBuiltin": false
            }
          }
        }
      ],
      "filters":[
        "/^\\d$/"
      ]
    },
    {
      "label": "Global",
      "items": [
        {
          "source": "Global",
          "select": {
            "attributes": {
              "isBuiltin": true
            }
          }
        }
      ]
    }
  ]
  ...
}

// Previous implementations
{
  ...
  "variableCategories": [
    {
      "label": "Local",
      "source": "Local"
    },
    {
      "label": "Static",
      "source": "Static"
    },
    {
      "label": "Global",
      "source": "Global",
      "noduplicate": true,
      "matchers": [
        {
          "method": "exclude",
          "pattern": "^\\d+$"
        }
      ]
    },
    {
      "label": "Built-in Global",
      "source": "Global",
      "matchers": [
        {
          "builtin": true
        },
        {
          "method": "exclude",
          "pattern": "^\\d+$"
        }
      ]
    }
  ]
  ...
}

New variable categories can be shown or hidden using conditional expressions.

In the following example, the category that watches the expected and actual variables is only visible when unit tests are being run.

The visible field of the conditional expression is evaluated using AELL (AutoHotkey Expression Like Language).

AELL will be available in v2.0.0.


{
  ...
  "variablesCategories": [
    "Local",
    "Global",
    {
      "label": "UnitTest",
      "visible": "IsSet(UnitTest) && A_FuncName ~= \"i)test*\"",
      "items": [
        "expected",
        "actual"
      ]
    }
  ]
  ...
}