add code preview
This commit is contained in:
Generated
+404
-3
@@ -1018,9 +1018,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.4.1"
|
version = "1.2.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9066c49992464636f92905fa096ec58baaa4d57ec19a5c096c68d3e25ef3d136"
|
checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -3522,6 +3522,41 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"tree-sitter",
|
||||||
|
"tree-sitter-astro-next",
|
||||||
|
"tree-sitter-bash",
|
||||||
|
"tree-sitter-c",
|
||||||
|
"tree-sitter-c-sharp",
|
||||||
|
"tree-sitter-cmake",
|
||||||
|
"tree-sitter-cpp",
|
||||||
|
"tree-sitter-css",
|
||||||
|
"tree-sitter-diff",
|
||||||
|
"tree-sitter-elixir",
|
||||||
|
"tree-sitter-embedded-template",
|
||||||
|
"tree-sitter-go",
|
||||||
|
"tree-sitter-graphql",
|
||||||
|
"tree-sitter-html",
|
||||||
|
"tree-sitter-java",
|
||||||
|
"tree-sitter-javascript",
|
||||||
|
"tree-sitter-jsdoc",
|
||||||
|
"tree-sitter-json",
|
||||||
|
"tree-sitter-kotlin-sg",
|
||||||
|
"tree-sitter-lua",
|
||||||
|
"tree-sitter-make",
|
||||||
|
"tree-sitter-md",
|
||||||
|
"tree-sitter-php",
|
||||||
|
"tree-sitter-proto",
|
||||||
|
"tree-sitter-python",
|
||||||
|
"tree-sitter-ruby",
|
||||||
|
"tree-sitter-rust",
|
||||||
|
"tree-sitter-scala",
|
||||||
|
"tree-sitter-sequel",
|
||||||
|
"tree-sitter-svelte-next",
|
||||||
|
"tree-sitter-swift",
|
||||||
|
"tree-sitter-toml-ng",
|
||||||
|
"tree-sitter-typescript",
|
||||||
|
"tree-sitter-yaml",
|
||||||
|
"tree-sitter-zig",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"uuid",
|
"uuid",
|
||||||
"windows 0.58.0",
|
"windows 0.58.0",
|
||||||
@@ -8035,6 +8070,12 @@ version = "0.4.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6"
|
checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "streaming-iterator"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strict-num"
|
name = "strict-num"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -8361,7 +8402,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.3.4",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.1.4",
|
"rustix 1.1.4",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -8823,6 +8864,366 @@ dependencies = [
|
|||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter"
|
||||||
|
version = "0.26.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83c567a8e18ae93f20982c90370b16fd24023aeaf52f6052b96957ab253a0fec"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"regex",
|
||||||
|
"regex-syntax",
|
||||||
|
"serde_json",
|
||||||
|
"streaming-iterator",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-astro-next"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "794a4a59fc2d88e49b4bc41fef9522d77184a36f4e68bbaf545cd1eb2364c46e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-bash"
|
||||||
|
version = "0.23.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "329a4d48623ac337d42b1df84e81a1c9dbb2946907c102ca72db158c1964a52e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-c"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9b2eb57a55fed6b00812912e730b7a275cf4fe98bfd6a5d76263d4438371728"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-c-sharp"
|
||||||
|
version = "0.23.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1aac67f1ad71de1d6d39708d34811081c26dfa495658de6c14c34200849357c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-cmake"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "164e0c4f4236ec5ceff14824a5528615cf462e100467e49826442ff57d327061"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-cpp"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df2196ea9d47b4ab4a31b9297eaa5a5d19a0b121dceb9f118f6790ad0ab94743"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-css"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ad6489794d41350d12a7fbe520e5199f688618f43aace5443980d1ddcf1b29e"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-diff"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfe1e5ca280a65dfe5ba4205c1bcc84edf486464fed315db53dee6da9a335889"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-elixir"
|
||||||
|
version = "0.3.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66dd064a762ed95bfc29857fa3cb7403bb1e5cb88112de0f6341b7e47284ba40"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-embedded-template"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "790063ef14e5b67556abc0b3be0ed863fb41d65ee791cf8c0b20eb42a1fa46af"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-go"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b13d476345220dbe600147dd444165c5791bf85ef53e28acbedd46112ee18431"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-graphql"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efedc4cac157161cc23a0adc4553a2cedc908e1cd754b6cd033a919bb81ce5d6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-html"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "261b708e5d92061ede329babaaa427b819329a9d427a1d710abb0f67bbef63ee"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-java"
|
||||||
|
version = "0.23.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0aa6cbcdc8c679b214e616fd3300da67da0e492e066df01bcf5a5921a71e90d6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-javascript"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf40bf599e0416c16c125c3cec10ee5ddc7d1bb8b0c60fa5c4de249ad34dc1b1"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-jsdoc"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3862dfcb1038fc5e7812d7df14190afdeb7e1415288fd5f51f58395f8cb0faf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-json"
|
||||||
|
version = "0.24.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d727acca406c0020cffc6cf35516764f36c8e3dc4408e5ebe2cb35a947ec471"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-kotlin-sg"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06ec43ae3c12165d4ac08afe4e1f5fc6757ffe274fa7bd5af9007ef11ba4319"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-language"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-lua"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea992f4164d83f371ef1239ae178c4d4596c296c09055e9a48bb02a2760403af"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-make"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5998dc7cbcbdab19fae8aefef982bf2d6544513d8d2e69cc44aec4c63810104"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-md"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2efd398be546456c814598ee56c0f51769a77241511b4a58077815d120afa882"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-php"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d8c17c3ab69052c5eeaa7ff5cd972dd1bc25d1b97ee779fec391ad3b5df5592"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-proto"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e4360b434b5980fc397137ef29e1988619fef4159ac86fa7ac5777d459d3924"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-python"
|
||||||
|
version = "0.23.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d065aaa27f3aaceaf60c1f0e0ac09e1cb9eb8ed28e7bcdaa52129cffc7f4b04"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-ruby"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be0484ea4ef6bb9c575b4fdabde7e31340a8d2dbc7d52b321ac83da703249f95"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-rust"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439e577dbe07423ec2582ac62c7531120dbfccfa6e5f92406f93dd271a120e45"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-scala"
|
||||||
|
version = "0.23.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "efde5e68b4736e9eac17bfa296c6f104a26bffab363b365eb898c40a63c15d2f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-sequel"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d198ad3c319c02e43c21efa1ec796b837afcb96ffaef1a40c1978fbdcec7d17"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-svelte-next"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56f88190d0743e897c3e148a7e241aba0a8844b8afe816943851426e3f7b9753"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-swift"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe36052155b9dd69ca82b3b8f1b4ccfb2d867125ac1a4db1dd7331829242668c"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-toml-ng"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e9adc2c898ae49730e857d75be403da3f92bb81d8e37a2f918a08dd10de5ebb1"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-typescript"
|
||||||
|
version = "0.23.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c5f76ed8d947a75cc446d5fccd8b602ebf0cde64ccf2ffa434d873d7a575eff"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-yaml"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53c223db85f05e34794f065454843b0668ebc15d240ada63e2b5939f43ce7c97"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tree-sitter-zig"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab11fc124851b0db4dd5e55983bbd9631192e93238389dcd44521715e5d53e28"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"tree-sitter-language",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
|||||||
+3
-1
@@ -18,7 +18,9 @@ gpui_macos = { git = "https://github.com/zed-industries/zed" }
|
|||||||
gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
||||||
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
||||||
|
|
||||||
gpui-component = { git = "https://github.com/longbridge/gpui-component" }
|
# `tree-sitter-languages` enables syntax highlighting for the TextView
|
||||||
|
# code preview (fenced code blocks are highlighted with tree-sitter).
|
||||||
|
gpui-component = { git = "https://github.com/longbridge/gpui-component", features = ["tree-sitter-languages"] }
|
||||||
|
|
||||||
nostr = { git = "https://github.com/rust-nostr/nostr", features = ["nip59", "nip49", "nip44", "os-rng"] }
|
nostr = { git = "https://github.com/rust-nostr/nostr", features = ["nip59", "nip49", "nip44", "os-rng"] }
|
||||||
nostr-lmdb = { git = "https://github.com/rust-nostr/nostr" }
|
nostr-lmdb = { git = "https://github.com/rust-nostr/nostr" }
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
//! File explorer of the repository detail view: the file tree column and the
|
//! File explorer of the repository detail view: the file tree column and the
|
||||||
//! content column (README / file preview), backed by a persistent
|
//! content column (README / file preview), backed by persistent
|
||||||
//! [`TextViewState`] for markdown documents.
|
//! [`TextViewState`]s for markdown documents and code files.
|
||||||
|
|
||||||
use gpui::prelude::*;
|
use gpui::prelude::*;
|
||||||
use gpui::{AnyElement, Context, Entity, SharedString, WeakEntity, div, px};
|
use gpui::{AnyElement, Context, Entity, SharedString, WeakEntity, div, px};
|
||||||
|
use gpui_component::clipboard::Clipboard;
|
||||||
use gpui_component::list::ListItem;
|
use gpui_component::list::ListItem;
|
||||||
use gpui_component::spinner::Spinner;
|
use gpui_component::spinner::Spinner;
|
||||||
use gpui_component::text::{TextView, TextViewState};
|
use gpui_component::text::{TextView, TextViewState};
|
||||||
@@ -11,7 +12,7 @@ use gpui_component::tree::{TreeEntry, TreeState, tree};
|
|||||||
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
|
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
|
||||||
|
|
||||||
use super::RepoDetailView;
|
use super::RepoDetailView;
|
||||||
use super::helpers::{is_markdown_path, placeholder, plain_lines};
|
use super::helpers::{code_language, fenced_code, is_markdown_path, placeholder};
|
||||||
|
|
||||||
/// Width of the file explorer column.
|
/// Width of the file explorer column.
|
||||||
const TREE_WIDTH: f32 = 240.;
|
const TREE_WIDTH: f32 = 240.;
|
||||||
@@ -44,6 +45,28 @@ pub(super) struct MarkdownView {
|
|||||||
pub(super) state: Entity<TextViewState>,
|
pub(super) state: Entity<TextViewState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A code file loaded into a persistent [`TextViewState`], rendered as a
|
||||||
|
/// fenced code block so the markdown parser syntax-highlights it.
|
||||||
|
///
|
||||||
|
/// Same persistence rationale as [`MarkdownView`]: the state lives as long
|
||||||
|
/// as this view, so re-viewing the same file does not re-parse it, and
|
||||||
|
/// parsing happens on a background task.
|
||||||
|
pub(super) struct CodeView {
|
||||||
|
/// Source path, relative to the worktree root.
|
||||||
|
pub(super) path: SharedString,
|
||||||
|
pub(super) state: Entity<TextViewState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Spinner shown while a document is being loaded/parsed.
|
||||||
|
fn preview_spinner() -> AnyElement {
|
||||||
|
v_flex()
|
||||||
|
.size_full()
|
||||||
|
.items_center()
|
||||||
|
.justify_center()
|
||||||
|
.child(Spinner::new().small())
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
impl RepoDetailView {
|
impl RepoDetailView {
|
||||||
/// One row of the file tree: icon + name, indented by depth.
|
/// One row of the file tree: icon + name, indented by depth.
|
||||||
fn render_tree_item(
|
fn render_tree_item(
|
||||||
@@ -150,14 +173,11 @@ impl RepoDetailView {
|
|||||||
.into_any_element()
|
.into_any_element()
|
||||||
} else if let Some(path) = selected_file {
|
} else if let Some(path) = selected_file {
|
||||||
match self.files.get(path.as_ref()) {
|
match self.files.get(path.as_ref()) {
|
||||||
Some(FileContent::Text(text)) => {
|
Some(FileContent::Text(_)) => {
|
||||||
if is_markdown_path(path.as_ref()) {
|
if is_markdown_path(path.as_ref()) {
|
||||||
self.markdown_element(Some(path.as_ref()), cx)
|
self.markdown_element(Some(path.as_ref()), cx)
|
||||||
} else {
|
} else {
|
||||||
v_flex()
|
self.code_element(path.as_ref(), cx)
|
||||||
.size_full()
|
|
||||||
.children(plain_lines(text, cx))
|
|
||||||
.into_any_element()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(FileContent::Binary) => placeholder("Binary file — preview not supported", cx),
|
Some(FileContent::Binary) => placeholder("Binary file — preview not supported", cx),
|
||||||
@@ -197,15 +217,7 @@ impl RepoDetailView {
|
|||||||
.child(pane_title),
|
.child(pane_title),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(div().id("repo-content").flex_1().min_h_0().child(body))
|
||||||
div()
|
|
||||||
.id("repo-content-scroll")
|
|
||||||
.flex_1()
|
|
||||||
.min_h_0()
|
|
||||||
.p_4()
|
|
||||||
.overflow_y_scroll()
|
|
||||||
.child(body),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load `text` into the persistent markdown TextView state.
|
/// Load `text` into the persistent markdown TextView state.
|
||||||
@@ -228,26 +240,71 @@ impl RepoDetailView {
|
|||||||
/// The persistent markdown TextView for `path` (`None` = README), or a
|
/// The persistent markdown TextView for `path` (`None` = README), or a
|
||||||
/// spinner while the document is being loaded/parsed.
|
/// spinner while the document is being loaded/parsed.
|
||||||
fn markdown_element(&mut self, path: Option<&str>, _cx: &mut Context<Self>) -> AnyElement {
|
fn markdown_element(&mut self, path: Option<&str>, _cx: &mut Context<Self>) -> AnyElement {
|
||||||
let spinner = || {
|
|
||||||
v_flex()
|
|
||||||
.size_full()
|
|
||||||
.items_center()
|
|
||||||
.justify_center()
|
|
||||||
.child(Spinner::new().small())
|
|
||||||
.into_any_element()
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(md) = &self.md else {
|
let Some(md) = &self.md else {
|
||||||
return spinner();
|
return preview_spinner();
|
||||||
};
|
};
|
||||||
let ready = match path {
|
let ready = match path {
|
||||||
Some(path) => md.path.as_deref() == Some(path),
|
Some(path) => md.path.as_deref() == Some(path),
|
||||||
None => md.path.is_none(),
|
None => md.path.is_none(),
|
||||||
};
|
};
|
||||||
if !ready {
|
if !ready {
|
||||||
return spinner();
|
return preview_spinner();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextView::new(&md.state).selectable(true).into_any_element()
|
TextView::new(&md.state)
|
||||||
|
.selectable(true)
|
||||||
|
.scrollable(true)
|
||||||
|
.p_4()
|
||||||
|
.into_any_element()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load `text` into the persistent code TextView state for `path`.
|
||||||
|
///
|
||||||
|
/// The code is wrapped in a markdown fence (see [`fenced_code`]) so the
|
||||||
|
/// TextView renders it as a syntax-highlighted code block. Like
|
||||||
|
/// [`set_markdown`], the state is created empty and fed via `push_str`
|
||||||
|
/// so parsing happens on a background task instead of blocking the main
|
||||||
|
/// thread.
|
||||||
|
pub(super) fn set_code(&mut self, path: SharedString, text: &str, cx: &mut Context<Self>) {
|
||||||
|
let source = fenced_code(text, code_language(path.as_ref()));
|
||||||
|
let state = cx.new(|cx| TextViewState::markdown("", cx));
|
||||||
|
state.update(cx, |state, cx| state.push_str(&source, cx));
|
||||||
|
self.code = Some(CodeView { path, state });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The persistent code TextView for `path`, or a spinner while the file
|
||||||
|
/// is being loaded/parsed.
|
||||||
|
fn code_element(&mut self, path: &str, _cx: &mut Context<Self>) -> AnyElement {
|
||||||
|
let Some(code) = &self.code else {
|
||||||
|
return preview_spinner();
|
||||||
|
};
|
||||||
|
if code.path.as_ref() != path {
|
||||||
|
return preview_spinner();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView::new(&code.state)
|
||||||
|
.selectable(true)
|
||||||
|
.scrollable(true)
|
||||||
|
.p_4()
|
||||||
|
.code_block_actions(|code_block, _window, cx| {
|
||||||
|
let lang = code_block.lang().unwrap_or_default();
|
||||||
|
h_flex()
|
||||||
|
.gap_2()
|
||||||
|
.items_center()
|
||||||
|
.when(!lang.is_empty(), |this| {
|
||||||
|
this.child(
|
||||||
|
div()
|
||||||
|
.text_xs()
|
||||||
|
.text_color(cx.theme().muted_foreground)
|
||||||
|
.child(lang.clone()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.child(
|
||||||
|
Clipboard::new(format!("copy-code-{lang}"))
|
||||||
|
.value(code_block.code())
|
||||||
|
.tooltip("Copy code"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.into_any_element()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//! Pure helpers for the repository detail view: file-tree building, plain
|
//! Pure helpers for the repository detail view: file-tree building, code
|
||||||
//! text rendering and small element builders.
|
//! preview helpers and small element builders.
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
@@ -45,20 +45,85 @@ fn insert_path(items: &mut Vec<TreeItem>, parts: &[String], prefix: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render text with one element per line, preserving blank lines.
|
/// The markdown fence language for a file path, or `None` for plain text.
|
||||||
pub(super) fn plain_lines(text: &str, cx: &App) -> Vec<AnyElement> {
|
///
|
||||||
text.lines()
|
/// Names are chosen so `gpui_component`'s highlighter can resolve them
|
||||||
.map(|line| {
|
/// (`highlighter::Language::from_name` accepts short aliases such as `rs`
|
||||||
// A space keeps empty lines from collapsing to zero height.
|
/// and `js`).
|
||||||
let text = if line.is_empty() { " " } else { line };
|
pub(super) fn code_language(path: &str) -> Option<&'static str> {
|
||||||
div()
|
let name = Path::new(path)
|
||||||
.font_family(cx.theme().mono_font_family.clone())
|
.file_name()
|
||||||
.text_xs()
|
.and_then(|name| name.to_str())
|
||||||
.text_color(cx.theme().foreground)
|
.unwrap_or_default();
|
||||||
.child(text.to_string())
|
|
||||||
.into_any_element()
|
// Some common files are recognized by name rather than extension.
|
||||||
})
|
match name {
|
||||||
.collect()
|
"Makefile" | "makefile" => return Some("make"),
|
||||||
|
"CMakeLists.txt" => return Some("cmake"),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ext = Path::new(path).extension()?.to_str()?.to_ascii_lowercase();
|
||||||
|
Some(match ext.as_str() {
|
||||||
|
"rs" => "rust",
|
||||||
|
"toml" => "toml",
|
||||||
|
"json" | "jsonc" => "json",
|
||||||
|
"py" => "python",
|
||||||
|
"js" | "mjs" | "cjs" => "javascript",
|
||||||
|
"ts" | "mts" | "cts" => "typescript",
|
||||||
|
"tsx" | "jsx" => "tsx",
|
||||||
|
"go" => "go",
|
||||||
|
"c" | "h" => "c",
|
||||||
|
"cc" | "cpp" | "cxx" | "hh" | "hpp" | "hxx" => "cpp",
|
||||||
|
"cs" => "csharp",
|
||||||
|
"java" => "java",
|
||||||
|
"kt" | "kts" | "ktm" => "kotlin",
|
||||||
|
"swift" => "swift",
|
||||||
|
"php" | "phtml" => "php",
|
||||||
|
"rb" => "ruby",
|
||||||
|
"sh" | "bash" | "zsh" => "bash",
|
||||||
|
"yml" | "yaml" => "yaml",
|
||||||
|
"css" | "scss" | "sass" => "css",
|
||||||
|
"html" | "htm" => "html",
|
||||||
|
"lua" => "lua",
|
||||||
|
"sql" => "sql",
|
||||||
|
"proto" | "protobuf" => "proto",
|
||||||
|
"cmake" => "cmake",
|
||||||
|
"zig" => "zig",
|
||||||
|
"ex" | "exs" => "elixir",
|
||||||
|
"graphql" | "gql" => "graphql",
|
||||||
|
"diff" | "patch" => "diff",
|
||||||
|
"svelte" => "svelte",
|
||||||
|
"astro" => "astro",
|
||||||
|
"scala" => "scala",
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrap `code` in a fenced markdown code block tagged with `lang`, so the
|
||||||
|
/// markdown [`TextViewState`] renders it as a syntax-highlighted code block.
|
||||||
|
///
|
||||||
|
/// The fence is one backtick longer than the longest run of backticks in
|
||||||
|
/// `code`, so the content can never close the block early.
|
||||||
|
pub(super) fn fenced_code(code: &str, lang: Option<&str>) -> String {
|
||||||
|
// Split on non-backtick characters so the segments are runs of backticks.
|
||||||
|
let longest_run = code.split(|c| c != '`').map(str::len).max().unwrap_or(0);
|
||||||
|
let fence = "`".repeat((longest_run + 1).max(3));
|
||||||
|
|
||||||
|
let mut out =
|
||||||
|
String::with_capacity(code.len() + fence.len() * 2 + lang.map_or(1, |lang| lang.len() + 2));
|
||||||
|
out.push_str(&fence);
|
||||||
|
if let Some(lang) = lang {
|
||||||
|
out.push(' ');
|
||||||
|
out.push_str(lang);
|
||||||
|
}
|
||||||
|
out.push('\n');
|
||||||
|
out.push_str(code);
|
||||||
|
if !code.ends_with('\n') {
|
||||||
|
out.push('\n');
|
||||||
|
}
|
||||||
|
out.push_str(&fence);
|
||||||
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether a file path has a markdown extension.
|
/// Whether a file path has a markdown extension.
|
||||||
@@ -134,4 +199,39 @@ mod tests {
|
|||||||
assert_eq!(items[0].children[0].id, "a/b");
|
assert_eq!(items[0].children[0].id, "a/b");
|
||||||
assert_eq!(items[0].children[0].children[0].id, "a/b/c.txt");
|
assert_eq!(items[0].children[0].children[0].id, "a/b/c.txt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fenced_code_wraps_in_triple_backticks() {
|
||||||
|
let out = fenced_code("fn main() {}\n", Some("rust"));
|
||||||
|
assert_eq!(out, "``` rust\nfn main() {}\n```");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fenced_code_uses_longer_fence_than_content() {
|
||||||
|
let code = "let x = \"```\";\n`code`";
|
||||||
|
let out = fenced_code(code, None);
|
||||||
|
// The longest run of backticks in `code` is 3, so the fence is 4.
|
||||||
|
assert!(out.starts_with("````\n"));
|
||||||
|
assert!(out.ends_with("````"));
|
||||||
|
assert!(out.contains(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fenced_code_keeps_trailing_newline() {
|
||||||
|
assert_eq!(fenced_code("a\n", None), "```\na\n```");
|
||||||
|
assert_eq!(fenced_code("a", None), "```\na\n```");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn code_language_maps_extensions_and_names() {
|
||||||
|
assert_eq!(code_language("src/main.rs"), Some("rust"));
|
||||||
|
assert_eq!(code_language("Cargo.toml"), Some("toml"));
|
||||||
|
assert_eq!(code_language("app.js"), Some("javascript"));
|
||||||
|
assert_eq!(code_language("index.tsx"), Some("tsx"));
|
||||||
|
assert_eq!(code_language("Makefile"), Some("make"));
|
||||||
|
assert_eq!(code_language("CMakeLists.txt"), Some("cmake"));
|
||||||
|
assert_eq!(code_language("data.csv"), None);
|
||||||
|
assert_eq!(code_language("LICENSE"), None);
|
||||||
|
assert_eq!(code_language("README.md"), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use signed_state::{GitStore, RepoStore};
|
|||||||
mod browser;
|
mod browser;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
use browser::{FileContent, MAX_PREVIEW_BYTES, MarkdownView};
|
use browser::{CodeView, FileContent, MAX_PREVIEW_BYTES, MarkdownView};
|
||||||
use helpers::{build_tree_items, is_markdown_path};
|
use helpers::{build_tree_items, is_markdown_path};
|
||||||
|
|
||||||
/// Detail view of a repository: header, stats, a file explorer with README
|
/// Detail view of a repository: header, stats, a file explorer with README
|
||||||
@@ -34,6 +34,8 @@ pub struct RepoDetailView {
|
|||||||
worktree: Option<PathBuf>,
|
worktree: Option<PathBuf>,
|
||||||
/// Markdown document currently in the preview pane (README or a file).
|
/// Markdown document currently in the preview pane (README or a file).
|
||||||
md: Option<MarkdownView>,
|
md: Option<MarkdownView>,
|
||||||
|
/// Code file currently in the preview pane.
|
||||||
|
code: Option<CodeView>,
|
||||||
readme_name: Option<SharedString>,
|
readme_name: Option<SharedString>,
|
||||||
/// Currently previewed file (relative path) and its contents.
|
/// Currently previewed file (relative path) and its contents.
|
||||||
selected_file: Option<SharedString>,
|
selected_file: Option<SharedString>,
|
||||||
@@ -63,6 +65,7 @@ impl RepoDetailView {
|
|||||||
tree_state,
|
tree_state,
|
||||||
worktree: None,
|
worktree: None,
|
||||||
md: None,
|
md: None,
|
||||||
|
code: None,
|
||||||
readme_name: None,
|
readme_name: None,
|
||||||
selected_file: None,
|
selected_file: None,
|
||||||
files: HashMap::new(),
|
files: HashMap::new(),
|
||||||
@@ -150,9 +153,11 @@ impl RepoDetailView {
|
|||||||
Component::ParentDir | Component::RootDir | Component::Prefix(_)
|
Component::ParentDir | Component::RootDir | Component::Prefix(_)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let Some(worktree) = self.worktree.clone() else {
|
let Some(worktree) = self.worktree.clone() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
if unsafe_path {
|
if unsafe_path {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -186,13 +191,19 @@ impl RepoDetailView {
|
|||||||
this.loading_files.remove(&path);
|
this.loading_files.remove(&path);
|
||||||
match content {
|
match content {
|
||||||
Ok(kind) => {
|
Ok(kind) => {
|
||||||
if let FileContent::Text(text) = &kind
|
if let FileContent::Text(text) = &kind {
|
||||||
&& is_markdown_path(&path)
|
if is_markdown_path(&path) {
|
||||||
{
|
let same = this.md.as_ref().map(|md| md.path.as_deref())
|
||||||
let same = this.md.as_ref().map(|md| md.path.as_deref())
|
== Some(Some(path.as_str()));
|
||||||
== Some(Some(path.as_str()));
|
if !same {
|
||||||
if !same {
|
this.set_markdown(Some(path.clone().into()), text, cx);
|
||||||
this.set_markdown(Some(path.clone().into()), text, cx);
|
}
|
||||||
|
} else {
|
||||||
|
let same = this.code.as_ref().map(|code| code.path.as_str())
|
||||||
|
== Some(path.as_str());
|
||||||
|
if !same {
|
||||||
|
this.set_code(path.clone().into(), text, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.files.insert(path, kind);
|
this.files.insert(path, kind);
|
||||||
@@ -280,6 +291,7 @@ impl Render for RepoDetailView {
|
|||||||
.pt_2()
|
.pt_2()
|
||||||
.pb_4()
|
.pb_4()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
.items_start()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.border_b_1()
|
.border_b_1()
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
|
|||||||
Reference in New Issue
Block a user