Skip to content

Commit

Permalink
fix: first line syntex detection is not working while typing
Browse files Browse the repository at this point in the history
Signed-off-by: Jack Cherng <[email protected]>
  • Loading branch information
jfcherng committed Feb 23, 2024
1 parent 01fd262 commit 39e2b8c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
30 changes: 21 additions & 9 deletions plugin/commands/auto_set_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,30 +171,42 @@ def _assign_syntax_with_plugin_rules(


def _assign_syntax_with_first_line(view: sublime.View, event: ListenerEvent | None = None) -> bool:
if not (view_snapshot := G.view_snapshot_collection.get_by_view(view)):
return False

# Note that this only works for files under some circumstances.
# This is to prevent from, for example, changing a ".erb" (Rails HTML template) file into HTML syntax.
# But we want to change a file whose name is "cpp" with a Python shebang into Python syntax.
def assign_by_shebang(view_snapshot: ViewSnapshot) -> sublime.Syntax | None:
def _prefer_shebang(view_snapshot: ViewSnapshot) -> sublime.Syntax | None:
if (
view_snapshot.syntax
and not is_plaintext_syntax(view_snapshot.syntax)
and ("." not in view_snapshot.file_name_unhidden or view_snapshot.first_line.startswith("#!"))
view_snapshot.first_line.startswith("#!")
and (syntax := sublime.find_syntax_for_file("", view_snapshot.first_line))
and not is_plaintext_syntax(syntax)
):
return syntax
return None

def assign_by_vim_modeline(view_snapshot: ViewSnapshot) -> sublime.Syntax | None:
def _prefer_general_first_line(view_snapshot: ViewSnapshot) -> sublime.Syntax | None:
if (
not view_snapshot.file_extensions
and (syntax := sublime.find_syntax_for_file(view_snapshot.file_name_unhidden, view_snapshot.first_line))
and not is_plaintext_syntax(syntax)
):
return syntax
return None

def _prefer_vim_modeline(view_snapshot: ViewSnapshot) -> sublime.Syntax | None:
for match in RE_VIM_SYNTAX_LINE.finditer(view_snapshot.content):
if syntax := find_syntax_by_syntax_like(match.group("syntax")):
return syntax
return None

for checker in (assign_by_shebang, assign_by_vim_modeline):
if not (view_snapshot := G.view_snapshot_collection.get_by_view(view)):
return False

# It's potentially that a first line of a syntax is a prefix of another syntax's.
# Thus if the user is typing, only try assigning syntax if this is not triggered by the first line.
if event is ListenerEvent.MODIFY and view_snapshot.caret_rowcol[0] == 0:
return False

for checker in (_prefer_shebang, _prefer_vim_modeline, _prefer_general_first_line):
if syntax := checker(view_snapshot):
return assign_syntax_to_view(
view,
Expand Down
8 changes: 8 additions & 0 deletions plugin/snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ class ViewSnapshot:
"""The path object of this file. `None` if not on a disk."""
syntax: sublime.Syntax | None
"""The syntax object. Note that the value is as-is when it's cached."""
caret_rowcol: tuple[int, int] = (-1, -1)
"""The 0-indexed `(row, column)` of the first caret visually. -1 if no caret."""

@property
def file_extensions(self) -> list[str]:
"""The file extensions. Empty list if not on a disk."""
return self.path_obj.suffixes if self.path_obj else []

@property
def file_name(self) -> str:
Expand Down Expand Up @@ -82,6 +89,7 @@ def add(self, cache_id: str, view: sublime.View) -> None:
line_count=view.rowcol(view.size())[0] + 1,
path_obj=path,
syntax=view.syntax(),
caret_rowcol=view.rowcol(sels[0].b) if len(sels := view.sel()) else (-1, -1),
)

def get_by_view(self, view: sublime.View) -> ViewSnapshot | None:
Expand Down

0 comments on commit 39e2b8c

Please sign in to comment.