Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(text-area): new languages #4160

Merged
merged 3 commits into from
Mar 30, 2024

Conversation

juftin
Copy link
Contributor

@juftin juftin commented Feb 14, 2024

NOTE:

This PR is still in draft state. More details to come

This PR adds new builtin languages for the TextArea Widget.

Commits

Language Sources

The following us a summary for where each .scm file originated from. This was done by parsing the latest grantjenks/py-tree-sitter-languages/repos.txt - everything was checked on the v1.10.2 tag.

Language Name Link License
erlang https://github.com/WhatsApp/tree-sitter-erlang/blob/54b6f814f43c4eac81eeedefaa7cc8762fec6683/queries/highlights.scm apache-2.0
elisp https://github.com/Wilfred/tree-sitter-elisp/blob/4b0e4a3891337514126ec72c7af394c0ff2cf48c/queries/highlights.scm mit
make https://github.com/alemuller/tree-sitter-make/blob/a4b9187417d6be349ee5fd4b6e77b4172c6827dd/queries/highlights.scm mit
dockerfile https://github.com/camdencheek/tree-sitter-dockerfile/blob/25c71d6a24cdba8f0c74ef40d4d2d93defd7e196/queries/highlights.scm mit
gomod https://github.com/camdencheek/tree-sitter-go-mod/blob/4a65743dbc2bb3094114dd2b43da03c820aa5234/queries/highlights.scm mit
sqlite https://github.com/dhcmrlchtdj/tree-sitter-sqlite/blob/993be0a91c0c90b0cc7799e6ff65922390e2cefe/queries/highlights.scm mit
elixir https://github.com/elixir-lang/tree-sitter-elixir/blob/11426c5fd20eef360d5ecaf10729191f6bc5d715/queries/highlights.scm apache-2.0
elm https://github.com/elm-tooling/tree-sitter-elm/blob/c26afd7f2316f689410a1622f1780eff054994b1/queries/highlights.scm mit
kotlin https://github.com/fwcd/tree-sitter-kotlin/blob/0ef87892401bb01c84b40916e1f150197bc134b1/queries/highlights.scm mit
objc https://github.com/jiyee/tree-sitter-objc/blob/afec0de5a32d5894070b67932d6ff09e4f7c5879/queries/highlights.scm mit
sql https://github.com/m-novikov/tree-sitter-sql/blob/218b672499729ef71e4d66a949e4a1614488aeaa/queries/highlights.scm mit
r https://github.com/r-lib/tree-sitter-r/blob/c55f8b4dfaa32c80ddef6c0ac0e79b05cb0cbf57/queries/highlights.scm mit
dot https://github.com/rydesun/tree-sitter-dot/blob/917230743aa10f45a408fea2ddb54bbbf5fbe7b7/queries/highlights.scm mit
hack https://github.com/slackhq/tree-sitter-hack/blob/fca1e294f6dce8ec5659233a6a21f5bd0ed5b4f2/queries/highlights.scm mit
fortran https://github.com/stadelmanma/tree-sitter-fortran/blob/f73d473e3530862dee7cbb38520f28824e7804f6/queries/highlights.scm mit
bash https://github.com/tree-sitter/tree-sitter-bash/blob/f7239f638d3dc16762563a9027faeee518ce1bd9/queries/highlights.scm mit
c https://github.com/tree-sitter/tree-sitter-c/blob/34f4c7e751f4d661be3e23682fe2631d6615141d/queries/highlights.scm mit
c_sharp https://github.com/tree-sitter/tree-sitter-c-sharp/blob/dd5e59721a5f8dae34604060833902b882023aaf/queries/highlights.scm mit
cpp https://github.com/tree-sitter/tree-sitter-cpp/blob/a71474021410973b29bfe99440d57bcd750246b1/queries/highlights.scm mit
css https://github.com/tree-sitter/tree-sitter-css/blob/98c7b3dceb24f1ee17f1322f3947e55638251c37/queries/highlights.scm mit
embedded_template https://github.com/tree-sitter/tree-sitter-embedded-template/blob/203f7bd3c1bbfbd98fc19add4b8fcb213c059205/queries/highlights.scm mit
go https://github.com/tree-sitter/tree-sitter-go/blob/ff86c7f1734873c8c4874ca4dd95603695686d7a/queries/highlights.scm mit
haskell https://github.com/tree-sitter/tree-sitter-haskell/blob/dd924b8df1eb76261f009e149fc6f3291c5081c2/queries/highlights.scm mit
html https://github.com/tree-sitter/tree-sitter-html/blob/949b78051835564bca937565241e5e337d838502/queries/highlights.scm mit
java https://github.com/tree-sitter/tree-sitter-java/blob/2b57cd9541f9fd3a89207d054ce8fbe72657c444/queries/highlights.scm mit
javascript https://github.com/tree-sitter/tree-sitter-javascript/blob/f1e5a09b8d02f8209a68249c93f0ad647b228e6e/queries/highlights.scm mit
jsdoc https://github.com/tree-sitter/tree-sitter-jsdoc/blob/d01984de49927c979b46ea5c01b78c8ddd79baf9/queries/highlights.scm mit
json https://github.com/tree-sitter/tree-sitter-json/blob/3fef30de8aee74600f25ec2e319b62a1a870d51e/queries/highlights.scm mit
ocaml https://github.com/tree-sitter/tree-sitter-ocaml/blob/4abfdc1c7af2c6c77a370aee974627be1c285b3b/queries/highlights.scm mit
php https://github.com/tree-sitter/tree-sitter-php/blob/33e30169e6f9bb29845c80afaa62a4a87f23f6d6/queries/highlights.scm mit
python https://github.com/tree-sitter/tree-sitter-python/blob/4bfdd9033a2225cc95032ce77066b7aeca9e2efc/queries/highlights.scm mit

Missing Languages

Languages without explicit license

Languages without highlights.scm file

It's possible these have other .scm files. See grantjenks/py-tree-sitter-languages/repos.txt for links

  • tree-sitter-fixed-form-fortran
  • tree-sitter-julia
  • tree-sitter-lua
  • tree-sitter-markdown
  • tree-sitter-perl
  • tree-sitter-rst
  • tree-sitter-tsq
  • tree-sitter-yaml

@@ -1,13 +1,43 @@
BUILTIN_LANGUAGES = sorted(
Copy link
Contributor Author

@juftin juftin Feb 14, 2024

Choose a reason for hiding this comment

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

I've found the TheRenegadeCoder/sample-programs repo useful for checking how these languages render.

App for Testing

"""
TextArea Example
"""

import os
import pathlib
from traceback import format_exc
from typing import Any, ClassVar

import click

from textual import on
from textual.app import ComposeResult, App
from textual.binding import BindingType, Binding
from textual.containers import Horizontal
from textual.widgets import TextArea, DirectoryTree, Header, Footer

KNOWN_EXTENSIONS = {
    "bash": [".sh", ".bash"],
    "c": [".c"],
    "c_sharp": [".cs"],
    "cpp": [".cpp", ".hpp", ".h"],
    "css": [".css"],
    "dockerfile": ["Dockerfile"],
    "dot": [".dot"],
    "elisp": [".el"],
    "elixir": [".ex", ".exs"],
    "elm": [".elm"],
    "embedded_template": [".et"],
    "erlang": [".erl", ".hrl"],
    "fortran": [".f", ".f90", ".f95", ".f03", ".f08", ".f18", ".for", ".f77"],
    "go": [".go"],
    "gomod": ["go.mod", "go.sum"],
    "hack": [".hh"],
    "haskell": [".hs"],
    "html": [".html", ".htm"],
    "java": [".java"],
    "javascript": [".js", ".jsx"],
    "jsdoc": [".jsdoc"],
    "json": [".json"],
    "kotlin": [".kt"],
    "make": ["Makefile", "makefile", "GNUmakefile"],
    "markdown": [".md", ".markdown", ".mdown", ".mkdn"],
    "objc": [".m", ".mm"],
    "ocaml": [".ml", ".mli"],
    "php": [".php", ".php5", ".php7"],
    "python": [".py"],
    "r": [".r"],
    "regex": [".regex"],
    "ruby": [".rb", ".erb"],
    "rust": [".rs"],
    "scala": [".scala"],
    "sql": [".sql"],
    "sqlite": [".sqlite"],
    "toml": [".toml"],
    "typescript": [".ts", ".tsx"],
    "yaml": [".yaml", ".yml"],
}

EXTENSION_TO_LANGUAGE_MAPPING = {
    extension: language
    for language, extensions in KNOWN_EXTENSIONS.items()
    for extension in extensions
}


class TextAreaApp(App):
    CSS: ClassVar[
        str
    ] = """
    DirectoryTree {
        width: auto;
    }
    """

    BINDINGS: ClassVar[list[BindingType]] = [
        Binding("q", "quit", "Quit", show=True, priority=True),
        Binding("t", "theme", "Change Theme", show=True, priority=True),
    ]

    def __init__(self, path: os.PathLike, *args: Any, **kwargs: Any) -> None:
        super().__init__(*args, **kwargs)
        self.path = pathlib.Path(path)
        self.directory_tree = DirectoryTree(path=self.path)
        self.text_area = TextArea(
            theme="monokai",
            soft_wrap=False,
            show_line_numbers=True,
        )

    def compose(self) -> ComposeResult:
        yield Header()
        yield Horizontal(self.directory_tree, self.text_area)
        yield Footer()

    @on(DirectoryTree.FileSelected)
    def handle_file_selected(self, event: DirectoryTree.FileSelected) -> None:
        self.path = pathlib.Path(event.path)
        try:
            new_text = event.path.read_text()
            extension_mapping = EXTENSION_TO_LANGUAGE_MAPPING.get(
                self.path.suffix.lower()
            )
            filename_mapping = EXTENSION_TO_LANGUAGE_MAPPING.get(self.path.name)
            language = extension_mapping or filename_mapping or "regex"
            self.text_area.text = new_text
            self.text_area.language = language
        except:  # noqa
            self.text_area.language = "regex"
            self.text_area.text = f"Error: {format_exc()}"
        finally:
            self.sub_title = f"[{self.text_area.language}] [{self.text_area.theme}]"

    def action_theme(self) -> None:
        all_themes = list(self.text_area.available_themes)
        current_index = all_themes.index(self.text_area.theme)
        next_index = (current_index + 1) % len(all_themes)
        self.text_area.theme = all_themes[next_index]
        self.sub_title = f"[{self.text_area.language}] [{self.text_area.theme}]"


@click.command()
@click.argument(
    "path", type=click.Path(exists=True, dir_okay=True, file_okay=False), default="."
)
def cli(path: os.PathLike) -> None:
    """
    TextArea CLI
    """
    app = TextAreaApp(path=path)
    app.run()


if __name__ == "__main__":
    cli()

"toml",
"typescript",
Copy link
Contributor Author

@juftin juftin Feb 14, 2024

Choose a reason for hiding this comment

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

Typescript has issues

NameError: Invalid node type satisfies

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I've found that this means the parser and highlights file is out of sync: the highlight query file has been updated to refer to a node type that the parser is unaware of. Usually moving to an older version of the highlights file (the version that "aligns" with the parser) fixes the problem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh, you're right. Once I pin on tree-sitter-languages==1.10.2, which is the version I used to map to the .scm files, everything works.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

typescript highlighting is non existent though after the new version pinning
image

Copy link
Contributor

@TomJGooding TomJGooding Feb 22, 2024

Choose a reason for hiding this comment

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

EDIT: See #4160 (comment)

@@ -1,64 +1,13 @@
(tag_name) @tag
(erroneous_end_tag_name) @html.end_tag_error
(erroneous_end_tag_name) @tag.error
Copy link
Member

Choose a reason for hiding this comment

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

We'll have to be mindful about changing existing highlight queries as it'll break features of some themes. For example, @html.end_tag_error is used in a couple of builtin themes:

"html.end_tag_error": Style(color="red", underline=True),

Copy link
Member

@darrenburns darrenburns Feb 15, 2024

Choose a reason for hiding this comment

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

Note that the @html.end_tag_error is completely arbitrary (a choice by us), so we could call it anything we want. However, if anyone has created their own theme it would no longer map correctly if we change it.

@TomJGooding
Copy link
Contributor

TomJGooding commented Feb 22, 2024

I'd recommend reading the section on Syntax Highlighting in the TextArea docs. The syntax highlighting won't work simply by including the highlights scm file, you would need to map the @symbol names to a Rich style in the theme.

For example if you take a look at the queries in typescript.scm, there's currently is no mapping for names like@type which is why you aren't seeing any highlighting.

@juftin
Copy link
Contributor Author

juftin commented Mar 4, 2024

I'd recommend reading the section on Syntax Highlighting in the TextArea docs. The syntax highlighting won't work simply by including the highlights scm file, you would need to map the @symbol names to a Rich style in the theme.

😞 dang - I was really hoping the hard part was done on this. I will take a closer look as I get some more time on this. Any assistance from tree-sitter <-> textual SMEs is appreciated.

@willmcgugan willmcgugan merged commit c8d6436 into Textualize:main Mar 30, 2024
1 check passed
@darrenburns
Copy link
Member

darrenburns commented Apr 1, 2024

I branched off of this and checked things work for a few popular languages in #4350 - when Will merged it I think it automatically closed this one.

We're still open to other new languages though, but I think it'll need to be a new PR now!

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.

4 participants