diff --git a/.gitmodules b/.gitmodules index d562763bb5..83cd442dc9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1166,6 +1166,9 @@ [submodule "vendor/grammars/turtle.tmbundle"] path = vendor/grammars/turtle.tmbundle url = https://github.com/peta/turtle.tmbundle +[submodule "vendor/grammars/typst-grammar"] + path = vendor/grammars/typst-grammar + url = https://github.com/michidk/typst-grammar.git [submodule "vendor/grammars/verilog.tmbundle"] path = vendor/grammars/verilog.tmbundle url = https://github.com/textmate/verilog.tmbundle diff --git a/grammars.yml b/grammars.yml index 73bfe17616..465408c6b7 100644 --- a/grammars.yml +++ b/grammars.yml @@ -1047,6 +1047,8 @@ vendor/grammars/toml.tmbundle: vendor/grammars/turtle.tmbundle: - source.sparql - source.turtle +vendor/grammars/typst-grammar: +- source.typ vendor/grammars/verilog.tmbundle: - source.verilog vendor/grammars/vhdl: diff --git a/lib/linguist/heuristics.yml b/lib/linguist/heuristics.yml index 46c66df7dd..1e6e9b2e3e 100644 --- a/lib/linguist/heuristics.yml +++ b/lib/linguist/heuristics.yml @@ -764,6 +764,11 @@ disambiguations: # HACK: This is a contrived use of heuristics needed to address # an unusual edge-case. See https://git.io/JULye for discussion. - language: Text +- extensions: ['.typ'] + rules: + - language: Typst + pattern: '^#(import|show|let|set)' + - language: XML - extensions: ['.url'] rules: - language: INI diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index af779c91e6..c6238eac10 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -7112,6 +7112,16 @@ TypeScript: codemirror_mode: javascript codemirror_mime_type: application/typescript language_id: 378 +Typst: + type: programming + color: "#239dad" + aliases: + - typ + extensions: + - ".typ" + tm_scope: source.typ + ace_mode: text + language_id: 704730682 Unified Parallel C: type: programming color: "#4e3617" @@ -7722,6 +7732,7 @@ XML: - ".tml" - ".ts" - ".tsx" + - ".typ" - ".ui" - ".urdf" - ".ux" diff --git a/samples/Typst/fiction.typ b/samples/Typst/fiction.typ new file mode 100644 index 0000000000..b7ef6a8943 --- /dev/null +++ b/samples/Typst/fiction.typ @@ -0,0 +1,168 @@ +// This function gets your whole document as its `body` and formats +// it as a simple fiction book. +#let book( + // The book's title. + title: "Book title", + + // The book's author. + author: "Author", + + // The paper size to use. + paper: "iso-b5", + + // A dedication to display on the third page. + dedication: none, + + // Details about the book's publisher that are + // display on the second page. + publishing-info: none, + + // The book's content. + body, +) = { + // Set the document's metadata. + set document(title: title, author: author) + + // Set the body font. TeX Gyre Pagella is a free alternative + // to Palatino. + set text(font: "TeX Gyre Pagella") + + // Configure the page properties. + set page( + paper: paper, + margin: (bottom: 1.75cm, top: 2.25cm), + ) + + // The first page. + page(align(center + horizon)[ + #text(2em)[*#title*] + #v(2em, weak: true) + #text(1.6em, author) + ]) + + // Display publisher info at the bottom of the second page. + if publishing-info != none { + align(center + bottom, text(0.8em, publishing-info)) + } + + pagebreak() + + // Display the dedication at the top of the third page. + if dedication != none { + v(15%) + align(center, strong(dedication)) + } + + // Books like their empty pages. + pagebreak() + pagebreak() + + // Configure paragraph properties. + set par(leading: 0.78em, first-line-indent: 12pt, justify: true) + show par: set block(spacing: 0.78em) + + // Start with a chapter outline. + outline(title: [Chapters]) + + // Configure page properties. + set page( + numbering: "1", + + // The header always contains the book title on odd pages and + // the chapter title on even pages, unless the page is one + // the starts a chapter (the chapter title is obvious then). + header: locate(loc => { + // Are we on an odd page? + let i = counter(page).at(loc).first() + if calc.odd(i) { + return text(0.95em, smallcaps(title)) + } + + // Are we on a page that starts a chapter? (We also check + // the previous page because some headings contain pagebreaks.) + let all = query(heading, loc) + if all.any(it => it.location().page() in (i - 1, i)) { + return + } + + // Find the heading of the section we are currently in. + let before = query(heading, before: loc) + if before != () { + align(right, text(0.95em, smallcaps(before.last().body))) + } + }), + ) + + // Configure chapter headings. + show heading.where(level: 1): it => { + // Always start on even pages. + pagebreak() + counter(page).display(i => if calc.odd(i) { + pagebreak() + }) + + // Create the heading numbering. + let number = if it.numbering != none { + counter(heading).display(it.numbering) + h(7pt, weak: true) + } + + v(5%) + text(2em, weight: 700, block([#number #it.body])) + v(1.25em) + } + show heading: set text(11pt, weight: 400) + + body +} + +#show: book.with( + title: "Liam's Playlist", + author: "Janet Doe", + dedication: [for Rachel], + publishing-info: [ + UK Publishing, Inc. \ + 6 Abbey Road \ + Vaughnham, 1PX 8A3 + + #link("https://example.co.uk/") + + 971-1-XXXXXX-XX-X + ], +) + += Mondays +Liam hated Mondays. He hated waking up to the sound of his dad's old car sputtering to life outside his window. He hated the smell of burnt toast and instant coffee that filled the kitchen. He hated the sight of his mum's tired face as she handed him his lunch bag and kissed him goodbye. He hated the feel of his worn-out uniform and backpack as he walked to the bus stop. He hated the noise of the other kids on the bus, talking about their weekend plans and their latest crushes. He hated the fact that he had nothing to say to them, nothing to share, nothing to look forward to. + +He got off the bus at his school and made his way to his locker, avoiding eye contact with anyone who might notice him or worse, pick on him. He was used to being invisible, being ignored, being alone. He didn't have any friends at school, or anywhere else for that matter. He didn't have any hobbies or interests that made him stand out or fit in. He didn't have any dreams or goals that gave him hope or motivation. He just had his routine: wake up, go to school, come home, do homework, watch TV, go to bed. Repeat. + +He opened his locker and took out his books for his first class: English literature. He liked reading books sometimes, but he didn't like analyzing them or writing essays about them. He didn't see the point of studying something that had no relevance to his life or future. What did Shakespeare or Dickens have to do with him? What did he care about metaphors or themes or symbols? He just wanted to escape into a different world for a while, not dissect it. + +He closed his locker and headed to class. As he walked down the hall, he saw her: Alice Walker. She was new at school this year and she was beautiful. She had long blonde hair that cascaded over her shoulders like a waterfall. She had bright blue eyes that sparkled like diamonds in the sunlight. She had a perfect smile that lit up her face like a star in the night sky. + +But he knew it was impossible. She was out of his league. She was from another world. He sighed and continued walking towards English literature. He hated Mondays. + += Music +#lorem(1500) + += Magic +#lorem(600) + +/* += Mystery +#lorem(600) + += Money +#lorem(6000) + += Mistakes +#lorem(6000) + += Memory +#lorem(6000) + += Miracle +#lorem(6000) + += Monday again +#lorem(6000) diff --git a/samples/Typst/letter.typ b/samples/Typst/letter.typ new file mode 100644 index 0000000000..8ca0a673c7 --- /dev/null +++ b/samples/Typst/letter.typ @@ -0,0 +1,81 @@ +// This function gets your whole document as its `body` +// and formats it as a simple letter. +#let letter( + // The letter's sender, which is display at the top of the page. + sender: none, + + // The letter's recipient, which is displayed close to the top. + recipient: none, + + // The date, displayed to the right. + date: none, + + // The subject line. + subject: none, + + // The name with which the letter closes. + name: none, + + // The letter's content. + body +) = { + // Configure page and text properties. + set page(margin: (top: 2cm)) + set text(font: "PT Sans") + + // Display sender at top of page. If there's no sender + // add some hidden text to keep the same spacing. + text(9pt, if sender == none { + hide("a") + } else { + sender + }) + + v(1.8cm) + + // Display recipient. + recipient + + v(0.5cm) + + // Display date. If there's no date add some hidden + // text to keep the same spacing. + align(right, if date != none { + date + } else { + hide("a") + }) + + v(2cm) + + // Add the subject line, if any. + if subject != none { + pad(right: 10%, strong(subject)) + } + + // Add body and name. + body + v(1.25cm) + name +} + +#show: letter.with( + sender: [ + Jane Smith, Universal Exports, 1 Heavy Plaza, Morristown, NJ 07964 + ], + recipient: [ + Mr. John Doe \ + Acme Corp. \ + 123 Glennwood Ave \ + Quarto Creek, VA 22438 + ], + date: [Morristown, June 9th, 2023], + subject: [Revision of our Producrement Contract], + name: [Jane Smith \ Regional Director], +) + +Dear Joe, + +#lorem(99) + +Best, diff --git a/samples/XML/example.typ b/samples/XML/example.typ new file mode 100644 index 0000000000..7a0ac19014 --- /dev/null +++ b/samples/XML/example.typ @@ -0,0 +1,4 @@ + + + + diff --git a/test/test_heuristics.rb b/test/test_heuristics.rb index 92c4206c95..e602cae7a0 100755 --- a/test/test_heuristics.rb +++ b/test/test_heuristics.rb @@ -985,6 +985,13 @@ def test_txt_by_heuristics }) end + def test_typ_by_heuristics + assert_heuristics({ + "Typst" => all_fixtures("Typst", "*.typ"), + "XML" => all_fixtures("XML", "*.typ") + }) + end + def test_url_by_heuristics assert_heuristics({ "INI" => Dir.glob("#{fixtures_path}/Generic/url/INI/*"), diff --git a/vendor/README.md b/vendor/README.md index 3834626fca..e540b739f8 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -554,6 +554,7 @@ This is a list of grammars that Linguist selects to provide syntax highlighting - **Twig:** [Anomareh/PHP-Twig.tmbundle](https://github.com/Anomareh/PHP-Twig.tmbundle) - **Type Language:** [goodmind/language-typelanguage](https://github.com/goodmind/language-typelanguage) - **TypeScript:** [tree-sitter/tree-sitter-typescript](https://github.com/tree-sitter/tree-sitter-typescript) 🐌 +- **Typst:** [michidk/typst-grammar](https://github.com/michidk/typst-grammar) - **Unified Parallel C:** [textmate/c.tmbundle](https://github.com/textmate/c.tmbundle) - **Unity3D Asset:** [atom/language-yaml](https://github.com/atom/language-yaml) - **Unix Assembly:** [calculuswhiz/Assembly-Syntax-Definition](https://github.com/calculuswhiz/Assembly-Syntax-Definition) diff --git a/vendor/grammars/typst-grammar b/vendor/grammars/typst-grammar new file mode 160000 index 0000000000..180d59e6f4 --- /dev/null +++ b/vendor/grammars/typst-grammar @@ -0,0 +1 @@ +Subproject commit 180d59e6f4e09941d778b5fa6fc48d52211294a1 diff --git a/vendor/licenses/git_submodule/typst-grammar.dep.yml b/vendor/licenses/git_submodule/typst-grammar.dep.yml new file mode 100644 index 0000000000..7be63fb71c --- /dev/null +++ b/vendor/licenses/git_submodule/typst-grammar.dep.yml @@ -0,0 +1,27 @@ +--- +name: typst-grammar +version: 180d59e6f4e09941d778b5fa6fc48d52211294a1 +type: git_submodule +homepage: https://github.com/michidk/typst-grammar +license: mit +licenses: +- sources: LICENSE + text: | + The MIT License (MIT) + Copyright (c) 2023 Nathan Varner + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +notices: []