jfcherng-sublime / ST-AutoSetSyntax

Helps you set the syntax for a view automatically in various ways.
https://packagecontrol.io/packages/AutoSetSyntax
MIT License
23 stars 2 forks source link

enhancement idea: use `sublime.find_resources` to pick up recommended AutoSetSyntax rules from other packages #21

Open keith-hall opened 1 month ago

keith-hall commented 1 month ago

Hi,

Thanks for this really useful plugin. Sometimes I am developing syntax definition packages, and update my local User AutoSetSyntax.sublime-settings user_syntax_rules (and I plan to contribute those here as default_syntax_rules when time permits). But I had the idea, how cool it would be if AutoSetSyntax would automatically pick up "recommended" syntax rules from other packages (i.e. by using sublime.find_resources for specifically named files), and inject them between the default_syntax_rules and user_syntax_rules. So users can still override the behavior even on a project basis. The advantage would be:

It would be easier to manage my packages because I would be able to see what rules it ships with, rather than having to go to the AutoSetSyntax package's settings and manually look for what rules apply for my packages...

Hopefully with all the debugging tools AutoSetSyntax supplies, it wouldn't make maintenance harder for you if a package ships rules which confuse users...

jfcherng commented 1 month ago

It would be easier to manage my packages because I would be able to see what rules it ships with, rather than having to go to the AutoSetSyntax package's settings and manually look for what rules apply for my packages...

Would the output panel of this plugin help? image

✔ Change View(48, "C:/Users/jfcherng/Desktop/Jenkinsfile_aaa") syntax from "Plain Text" to "Jenkinsfile" because {'event': "<ListenerEvent.LOAD('load')>", 'reason': 'plugin rule', 'rule': SyntaxRule(comment='', syntax=Syntax('Packages/User/my_language/Jenkinsfile.sublime-syntax', 'Jenkinsfile', False, 'source.groovy.jenkinsfile'), syntaxes_name=('Jenkinsfile', 'scope:source.groovy'), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.name_contains_regex.NameContainsRegexConstraint object>", constraint_name='name_contains_regex', args=('^Jenkinsfile(?=\\b|_)',), kwargs={}, inverted=False),))), 'syntax': Syntax('Packages/User/my_language/Jenkinsfile.sublime-syntax', 'Jenkinsfile', False, 'source.groovy.jenkinsfile')}

Not too readable though.

jfcherng commented 1 month ago

how cool it would be if AutoSetSyntax would automatically pick up "recommended" syntax rules from other packages

That sounds like a standard has to be made for this. And I wonder how many syntax maintainers will join the party...

keith-hall commented 4 weeks ago

Would the output panel of this plugin help?

A little. Still not the same as having all the rules that relate to a package inside that package. That's one thing I don't like about Package Control for example, is that the "ST build range to package tag mapping" is done inside package control channel repository, instead of it being self contained.

That sounds like a standard has to be made for this.

Definitely :)

And I wonder how many syntax maintainers will join the party...

Good question. I have the idea that somehow advertising could help - for example I've seen a few plugins implemented as part of syntax packages just to set the syntax when a file is opened if the file path contains a certain folder name etc. That would be a perfect use case for delegating to AutoSetSyntax instead of maintaining plugin code. Some maintainers may be reluctant to delegate to another package, but IMHO AutoSetSyntax is as essential as PackageDev... Especially as core ST is too limiting. I plan to update some of my packages which are guilty of this to recommend installing AutoSetSyntax instead.

jfcherng commented 3 weeks ago

I have added a Syntax Rules Summary command, which shows

# === [AutoSetSyntax] Syntax Rules Summary === #
# You may use the following website to beautify this debug information.
# @link https://play.ruff.rs/?secondary=Format

########################
# Syntax Rules Summary #
########################

# Syntax: Apache Conf
SyntaxRule(comment='Apache config', syntax=Syntax('Packages/User/my_language/ApacheConf/ApacheConf.sublime-syntax', 'Apache Conf', False, 'source.apacheconf'), syntaxes_name=('scope:source.apacheconf',), selector='text.plain | source.nginx', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.path_contains_regex.PathContainsRegexConstraint object>", constraint_name='path_contains_regex', args=('\\b(?i:apache|httpd)(?:\\b|_).*/conf/.*\\.conf$',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('<(?:VirtualHost|Directory|Macro)(?:$|\\s)',), kwargs={}, inverted=False))))

# Syntax: Bash
SyntaxRule(comment='', syntax=Syntax('Packages/ShellScript/Bash.sublime-syntax', 'Bash', False, 'source.shell.bash'), syntaxes_name=('scope:source.shell.bash',), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.is_name.IsNameConstraint object>", constraint_name='is_name', args=('profile', '.bash_history'), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.name_contains_regex.NameContainsRegexConstraint object>", constraint_name='name_contains_regex', args=('\\.(?:bash|z(?:shrc|shenv|profile|login|logout))(?:\\.[^/]*)?$',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.first_line_contains_regex.FirstLineContainsRegexConstraint object>", constraint_name='first_line_contains_regex', args=('^\\s*#\\s+shellcheck\\s+shell=(?:bash|sh|zsh)',), kwargs={}, inverted=False))))
SyntaxRule(comment='Linux .env files', syntax=Syntax('Packages/ShellScript/Bash.sublime-syntax', 'Bash', False, 'source.shell.bash'), syntaxes_name=('/DotENV.', 'scope:source.shell.bash'), selector='', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.all.AllMatch object>", match_name='all', args=(), kwargs={}, rules=(MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.selector_matches.SelectorMatchesConstraint object>", constraint_name='selector_matches', args=('text.plain',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.is_hidden_syntax.IsHiddenSyntaxConstraint object>", constraint_name='is_hidden_syntax', args=(), kwargs={}, inverted=False))), MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.is_name.IsNameConstraint object>", constraint_name='is_name', args=('.envrc',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.name_contains_regex.NameContainsRegexConstraint object>", constraint_name='name_contains_regex', args=('\\.(?:env)(?:\\.[^/]*)?$',), kwargs={}, inverted=False))))))

# Syntax: C#
SyntaxRule(comment='', syntax=Syntax('Packages/C#/C#.sublime-syntax', 'C#', False, 'source.cs'), syntaxes_name=('scope:source.cs',), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.all.AllMatch object>", match_name='all', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^using\\s',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^namespace\\s',), kwargs={}, inverted=False))))

# Syntax: C++
SyntaxRule(comment='', syntax=Syntax('Packages/C++/C++.sublime-syntax', 'C++', False, 'source.c++'), syntaxes_name=('scope:source.c++',), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('(?:^|\\s)#include\\s*[<"]', '(?:^|\\s)#pragma\\s+(?:once|pack|(?:pop|push)_macro|warning)(?=$|\\s)', '(?:^|\\s)template\\s*<\\s*(?:class|typename)(?=$|\\s)', '\\b(?:const(?:eval|expr|init)|decltype|nullptr|(?:const|dynamic|reinterpret|static)_cast)(?=$|\\s)'), kwargs={}, inverted=False),)))

# Syntax: Diff
SyntaxRule(comment='', syntax=Syntax('Packages/Diff/Diff.sublime-syntax', 'Diff', False, 'source.diff'), syntaxes_name=('scope:source.diff',), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(MatchRule(match="<AutoSetSyntax.plugin.rules.matches.all.AllMatch object>", match_name='all', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^\\+{3} ',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^-{3} ',), kwargs={}, inverted=False))), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^@@ -\\d+,\\d+ \\+\\d+,\\d+ @@',), kwargs={}, inverted=False))))

# Syntax: Git Config
SyntaxRule(comment='', syntax=Syntax('Packages/Git Formats/Git Config.sublime-syntax', 'Git Config', False, 'text.git.config'), syntaxes_name=('scope:text.git.config',), selector='- text.git.config', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.any.AnyMatch object>", match_name='any', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.path_contains_regex.PathContainsRegexConstraint object>", constraint_name='path_contains_regex', args=('/\\.?git/config$',), kwargs={}, inverted=False),)))

# Syntax: Go
SyntaxRule(comment='', syntax=Syntax('Packages/Go/Go.sublime-syntax', 'Go', False, 'source.go'), syntaxes_name=('scope:source.go',), selector='text.plain', on_events=None, root_rule=MatchRule(match="<AutoSetSyntax.plugin.rules.matches.all.AllMatch object>", match_name='all', args=(), kwargs={}, rules=(ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^(?:package)\\s',), kwargs={}, inverted=False), ConstraintRule(constraint="<AutoSetSyntax.plugin.rules.constraints.contains_regex.ContainsRegexConstraint object>", constraint_name='contains_regex', args=('^(?:import|func|type)\\s',), kwargs={}, inverted=False))))

...
keith-hall commented 3 weeks ago

Thanks, looks useful! Have you considered using pprint.pp instead of repr in utils.stringify to avoid the need for manual reformatting for readibility?

jfcherng commented 3 weeks ago

Thanks, looks useful! Have you considered using pprint.pp instead of repr in utils.stringify to avoid the need for manual reformatting for readibility?

Not much helpful. You will still have something like ConstraintRule(constraint=<AutoSetSyntax.plugin.rules.constraints.is_name.IsNameConstraint object at 0x000001FC567AE1C0>, .... And I don't get any indented output somehow.

I would rather define .to_dict() method for objects and dump their JSON format. Or, probably just introduce pydantic, which also provides data validation.

jfcherng commented 3 weeks ago

Or, probably just introduce pydantic, which also provides data validation.

I have a working example in the refactor/pydantic branch. Merged into master.

jfcherng commented 3 weeks ago

Or, probably just introduce pydantic, which also provides data validation.

I have a working example in the refactor/pydantic branch.

One small issue. I don't want LSP-json to work on that generated view :(