├── syncat ├── config │ ├── style │ │ ├── active │ │ │ ├── agda.syncat │ │ │ ├── elm.syncat │ │ │ ├── eno.syncat │ │ │ ├── go.syncat │ │ │ ├── lua.syncat │ │ │ ├── php.syncat │ │ │ ├── c_sharp.syncat │ │ │ ├── clojure.syncat │ │ │ ├── ocaml.syncat │ │ │ ├── systemrdl.syncat │ │ │ ├── embedded_template.syncat │ │ │ ├── cpp.syncat │ │ │ ├── test.syncat │ │ │ ├── json.syncat │ │ │ ├── prolog.syncat │ │ │ ├── toml.syncat │ │ │ ├── yaml.syncat │ │ │ ├── syncat_stylesheet.syncat │ │ │ ├── typescript.syncat │ │ │ ├── .syncat │ │ │ ├── markdown.syncat │ │ │ ├── html.syncat │ │ │ ├── hcl.syncat │ │ │ ├── jsx.syncat │ │ │ ├── css.syncat │ │ │ ├── graphql.syncat │ │ │ ├── haskell.syncat │ │ │ ├── sql.syncat │ │ │ ├── regex.syncat │ │ │ ├── bash.syncat │ │ │ ├── paper.syncat │ │ │ ├── scala.syncat │ │ │ ├── swift.syncat │ │ │ ├── c.syncat │ │ │ ├── ruby.syncat │ │ │ ├── java.syncat │ │ │ ├── kotlin.syncat │ │ │ ├── javascript.syncat │ │ │ ├── python.syncat │ │ │ └── rust.syncat │ │ └── colours.syncat │ ├── .gitignore │ └── languages.toml ├── src │ ├── filter │ │ ├── mod.rs │ │ ├── line_endings.rs │ │ ├── squeeze_blank_lines.rs │ │ ├── line_numbers.rs │ │ ├── git.rs │ │ └── frame.rs │ ├── colorize │ │ ├── mod.rs │ │ ├── sexp.rs │ │ └── source.rs │ ├── error.rs │ ├── opts.rs │ ├── config.rs │ ├── line.rs │ ├── language.rs │ ├── main.rs │ └── meta_stylesheet.rs ├── Cargo.toml └── build.rs ├── tree-sitter-syncat-stylesheet ├── .gitignore ├── corpus │ ├── imports │ ├── tokens │ ├── negative-node │ ├── variables │ ├── any-child │ ├── also │ ├── sibling │ ├── exact-sibling │ ├── important-styles │ ├── token-pattern │ ├── multiple-selectors │ ├── groups │ ├── comments │ ├── named-groups │ ├── direct-child-specifier │ └── style-types ├── binding.gyp ├── bindings │ ├── node │ │ ├── index.js │ │ └── binding.cc │ └── rust │ │ ├── build.rs │ │ └── lib.rs ├── package.json ├── Cargo.toml ├── package-lock.json ├── grammar.js └── src │ ├── tree_sitter │ └── parser.h │ └── node-types.json ├── Cargo.toml ├── .gitattributes ├── .gitignore ├── syncat-stylesheet ├── package.json ├── src │ ├── lib.rs │ ├── parser.rs │ ├── resolver.rs │ ├── ast │ │ ├── variable.rs │ │ ├── style.rs │ │ ├── import.rs │ │ ├── mod.rs │ │ ├── node.rs │ │ ├── node_modifier.rs │ │ ├── declaration.rs │ │ ├── helper.rs │ │ ├── color.rs │ │ ├── stylesheet.rs │ │ ├── rule.rs │ │ ├── selector.rs │ │ ├── value.rs │ │ └── node_kind.rs │ ├── stylesheet │ │ ├── matches.rs │ │ ├── mod.rs │ │ └── query.rs │ ├── style │ │ ├── mod.rs │ │ └── value.rs │ └── error.rs ├── Cargo.toml ├── package-lock.json ├── build.rs ├── README.md └── node_modules │ └── tree-sitter-syncat-stylesheet │ └── src │ └── tree_sitter │ └── parser.h ├── .github ├── FUNDING.yml └── workflows │ ├── release.yaml │ └── rust.yml ├── LICENSE └── README.md /syncat/config/style/active/agda.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/elm.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/eno.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/go.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/lua.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/php.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/.gitignore: -------------------------------------------------------------------------------- 1 | languages/ 2 | -------------------------------------------------------------------------------- /syncat/config/style/active/c_sharp.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/clojure.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/ocaml.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/systemrdl.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncat/config/style/active/embedded_template.syncat: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /syncat/config/style/active/cpp.syncat: -------------------------------------------------------------------------------- 1 | import "./c.syncat"; 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "syncat", 5 | "syncat-stylesheet", 6 | ] 7 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/imports: -------------------------------------------------------------------------------- 1 | ======= 2 | Imports 3 | ======= 4 | 5 | import "test-file.syncat"; 6 | 7 | --- 8 | 9 | (stylesheet 10 | (import (string))) 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | tree-sitter-syncat-stylesheet/src/* linguist-generated=true 2 | tree-sitter-syncat-stylesheet/index.js linguist-generated=true 3 | tree-sitter-syncat-stylesheet/binding.gyp linguist-generated=true 4 | -------------------------------------------------------------------------------- /syncat/config/style/active/test.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | eq_divider, dash_divider { 4 | color: $keyword; 5 | } 6 | 7 | heading_name { 8 | color: $string; 9 | } 10 | 11 | identifier { 12 | color: $function; 13 | } 14 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/tokens: -------------------------------------------------------------------------------- 1 | ====== 2 | Tokens 3 | ====== 4 | 5 | block "{" {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (token (string))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/negative-node: -------------------------------------------------------------------------------- 1 | ============= 2 | Negative Node 3 | ============= 4 | 5 | node ! child {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (not (kind (name)))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | **/*.rs.bk 4 | tree-sitter-syncat-stylesheet/node_modules 5 | 6 | syncat-stylesheet/node_modules/* 7 | !syncat-stylesheet/node_modules/tree-sitter-* 8 | syncat-stylesheet/node_modules/tree-sitter-*/* 9 | !syncat-stylesheet/node_modules/tree-sitter-*/src 10 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/variables: -------------------------------------------------------------------------------- 1 | ========= 2 | Variables 3 | ========= 4 | 5 | $variable: "hello"; 6 | $variable: blue; 7 | 8 | --- 9 | 10 | (stylesheet 11 | (declaration (variable) (value (string))) 12 | (declaration (variable) (value (color (named_color))))) 13 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/any-child: -------------------------------------------------------------------------------- 1 | ================== 2 | Any child selector 3 | ================== 4 | 5 | root * hello { } 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (any)) (node (kind (name))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/also: -------------------------------------------------------------------------------- 1 | ============= 2 | Also modifier 3 | ============= 4 | 5 | node child & "text" {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (kind (name))) (node_modifier (also)) (node (token (string))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/sibling: -------------------------------------------------------------------------------- 1 | ================ 2 | Sibling Modifier 3 | ================ 4 | 5 | node first ~ second {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (kind (name))) (node_modifier (sibling)) (node (kind (name))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /syncat/config/style/active/json.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | pair > !* + string { 4 | color: $field; 5 | } 6 | 7 | value > string, 8 | pair ":" + string { 9 | color: $string; 10 | } 11 | 12 | number { 13 | color: $value; 14 | } 15 | 16 | true, false { 17 | color: $value; 18 | } 19 | 20 | null { 21 | color: $keyword; 22 | } 23 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/exact-sibling: -------------------------------------------------------------------------------- 1 | ======================= 2 | Direct sibling modifier 3 | ======================= 4 | 5 | node child + sibling {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors (selector (node (kind (name))) (node (kind (name))) (node_modifier (direct_sibling)) (node (kind (name))))) 12 | (styles))) 13 | -------------------------------------------------------------------------------- /syncat/src/filter/mod.rs: -------------------------------------------------------------------------------- 1 | mod frame; 2 | mod git; 3 | mod line_endings; 4 | mod line_numbers; 5 | mod squeeze_blank_lines; 6 | 7 | pub use self::frame::{frame_footer, frame_header}; 8 | pub use self::git::git; 9 | pub use self::line_endings::line_endings; 10 | pub use self::line_numbers::line_numbers; 11 | pub use self::squeeze_blank_lines::squeeze_blank_lines; 12 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/important-styles: -------------------------------------------------------------------------------- 1 | ================ 2 | Important styles 3 | ================ 4 | 5 | root { 6 | color: blue !; 7 | } 8 | 9 | --- 10 | 11 | (stylesheet 12 | (rule 13 | (selectors (selector (node (kind (name))))) 14 | (styles 15 | (style (name) (value (color (named_color))) (style_modifier (important)))))) 16 | -------------------------------------------------------------------------------- /syncat-stylesheet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "syncat-stylesheet", 3 | "version": "2.2.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "tree-sitter-syncat-stylesheet": "2.2.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/token-pattern: -------------------------------------------------------------------------------- 1 | ============== 2 | Token patterns 3 | ============== 4 | 5 | block /hello_.*/i { 6 | color: white; 7 | } 8 | 9 | --- 10 | 11 | (stylesheet 12 | (rule 13 | (selectors 14 | (selector (node (kind (name))) (node (token (regex))))) 15 | (styles 16 | (style (name) (value (color (named_color))))))) 17 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/multiple-selectors: -------------------------------------------------------------------------------- 1 | ================== 2 | Multiple selectors 3 | ================== 4 | 5 | hello world, second selector {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors 12 | (selector (node (kind (name))) (node (kind (name)))) 13 | (selector (node (kind (name))) (node (kind (name))))) 14 | (styles))) 15 | -------------------------------------------------------------------------------- /syncat/src/filter/line_endings.rs: -------------------------------------------------------------------------------- 1 | use crate::Opts; 2 | use crate::line::Line; 3 | 4 | pub fn line_endings( 5 | &Opts { 6 | show_line_endings, .. 7 | }: &Opts, 8 | source: Vec, 9 | ) -> Vec { 10 | if show_line_endings { 11 | source.into_iter().map(Line::with_line_ending).collect() 12 | } else { 13 | source 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/groups: -------------------------------------------------------------------------------- 1 | ====== 2 | Groups 3 | ====== 4 | 5 | root (group "code") + hello {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors 12 | (selector 13 | (node (kind (name))) 14 | (node (group (selector (node (kind (name))) (node (token (string)))))) 15 | (node_modifier (direct_sibling)) 16 | (node (kind (name))))) 17 | (styles))) 18 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/comments: -------------------------------------------------------------------------------- 1 | ======== 2 | Comments 3 | ======== 4 | 5 | // hello world 6 | 7 | test { 8 | // hello world 9 | italic: true; 10 | } 11 | 12 | // hello world 13 | 14 | --- 15 | 16 | (stylesheet 17 | (comment) 18 | (rule 19 | (selectors 20 | (selector (node (kind (name))))) 21 | (styles 22 | (comment) 23 | (style (name) (value (boolean))))) 24 | (comment)) 25 | -------------------------------------------------------------------------------- /syncat/config/style/active/prolog.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | comment { 4 | color: $comment; 5 | } 6 | 7 | number { 8 | color: $constant; 9 | } 10 | 11 | term > atom { 12 | color: $function; 13 | } 14 | 15 | values > atom { 16 | color: $type; 17 | } 18 | 19 | ":-", "is", "=", "\\=", "<", "<=", ">", ">=", "-", "+", "*", "/", "_" { 20 | color: $keyword; 21 | } 22 | 23 | var { 24 | color: $name; 25 | } 26 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_Syncat_stylesheet_binding", 5 | "include_dirs": [ 6 | " "[", 4 | array > "]" { 5 | color: $value; 6 | } 7 | 8 | boolean, float, integer { 9 | color: $value; 10 | } 11 | 12 | local_date, local_date_time, offset_date_time { 13 | color: $builtin; 14 | } 15 | 16 | key { 17 | color: $name; 18 | } 19 | 20 | string { 21 | color: $string; 22 | } 23 | 24 | comment { 25 | color: $comment; 26 | } 27 | -------------------------------------------------------------------------------- /syncat/config/style/active/yaml.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | block_mapping_pair ":", 4 | block_sequence_item "-", 5 | block_scalar "|" { 6 | color: $operator; 7 | } 8 | 9 | double_quote_scalar, 10 | single_quote_scalar, 11 | string_scalar, 12 | block_scalar { 13 | color: $string; 14 | } 15 | 16 | null_scalar, 17 | integer_scalar, 18 | float_scalar, 19 | boolean_scalar { 20 | color: $value; 21 | } 22 | 23 | comment { 24 | color: $comment; 25 | } 26 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/named-groups: -------------------------------------------------------------------------------- 1 | ============ 2 | Named groups 3 | ============ 4 | 5 | root ( group "code") + hello {} 6 | 7 | --- 8 | 9 | (stylesheet 10 | (rule 11 | (selectors 12 | (selector 13 | (node (kind (name))) 14 | (node (group (group_name (name)) (selector (node (kind (name))) (node (token (string)))))) 15 | (node_modifier (direct_sibling)) 16 | (node (kind (name))))) 17 | (styles))) 18 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/lib.rs: -------------------------------------------------------------------------------- 1 | use tree_sitter::Language; 2 | 3 | mod ast; 4 | mod error; 5 | mod parser; 6 | pub mod resolver; 7 | mod style; 8 | mod stylesheet; 9 | 10 | pub use ast::Color; 11 | pub use error::{Error, ErrorKind, Result}; 12 | pub use style::{FromValueError, Style, Value}; 13 | use stylesheet::{Matches, QuerySlice}; 14 | pub use stylesheet::{Query, Stylesheet}; 15 | 16 | unsafe extern "C" { 17 | fn tree_sitter_syncat_stylesheet() -> Language; 18 | } 19 | -------------------------------------------------------------------------------- /syncat/config/style/active/syncat_stylesheet.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | variable { color: $variable; } 4 | group_name { color: $variable; } 5 | 6 | kind { color: $type; } 7 | style name { color: $function; } 8 | color { color: $builtin; } 9 | number, boolean { color: $value; } 10 | string { color: $string; } 11 | regex { language: regex; } 12 | 13 | "&", ">", "!", "+", "~", "import" { color: $keyword; } 14 | 15 | comment { 16 | color: $comment; 17 | } 18 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/parser.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use tree_sitter::{Parser, Tree}; 3 | 4 | thread_local! { 5 | static PARSER: RefCell = RefCell::new({ 6 | let mut parser = Parser::new(); 7 | parser.set_language(&unsafe { crate::tree_sitter_syncat_stylesheet() }).unwrap(); 8 | parser 9 | }); 10 | } 11 | 12 | pub(crate) fn parse(source: impl AsRef<[u8]>) -> Option { 13 | PARSER.with(|parser| parser.borrow_mut().parse(source, None)) 14 | } 15 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/resolver.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | pub trait Resolver { 4 | type Error: std::error::Error + Sync + Send + 'static; 5 | 6 | fn read_to_string>(&self, path: P) -> Result; 7 | } 8 | 9 | pub struct FsResolver; 10 | 11 | impl Resolver for FsResolver { 12 | type Error = std::io::Error; 13 | 14 | fn read_to_string>(&self, path: P) -> Result { 15 | std::fs::read_to_string(path) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/variable.rs: -------------------------------------------------------------------------------- 1 | use super::helper::*; 2 | use tree_sitter::TreeCursor; 3 | 4 | #[derive(Clone, Eq, PartialEq, Hash, Debug)] 5 | pub(crate) struct Variable(pub(crate) String); 6 | 7 | impl Variable { 8 | pub(crate) fn name(&self) -> &str { 9 | &self.0[1..] 10 | } 11 | } 12 | 13 | impl FromSource for Variable { 14 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 15 | Ok(Self(text!(tree, source, "variable")?.to_string())) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /syncat-stylesheet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "syncat-stylesheet" 3 | description = "Parser for Syncat Stylesheets." 4 | homepage = "https://github.com/foxfriends/syncat" 5 | repository = "https://github.com/foxfriends/syncat" 6 | version = "3.6.0" 7 | authors = ["Cameron Eldridge "] 8 | license = "MIT" 9 | edition = "2024" 10 | 11 | [build-dependencies] 12 | cc = "1.0" 13 | 14 | [dependencies] 15 | ansi_term = { version = "0.12", optional = true } 16 | hex = "0.4" 17 | regex = "1.5" 18 | tree-sitter = "0.25" 19 | enquote = "1.0" 20 | -------------------------------------------------------------------------------- /syncat/config/style/colours.syncat: -------------------------------------------------------------------------------- 1 | $comment: brwhite; 2 | 3 | $variable: red; 4 | $module: red; 5 | $field: $variable; 6 | $name: $variable; 7 | 8 | $function: blue; 9 | 10 | $builtin: cyan; 11 | $meta: cyan; 12 | 13 | $keyword: purple; 14 | $operator: $keyword; 15 | 16 | $string: green; 17 | $interpolation: red; 18 | 19 | $value: bryellow; 20 | $constant: bryellow; 21 | $integer: $value; 22 | $boolean: $value; 23 | $float: $value; 24 | 25 | $type: yellow; 26 | $text: white; 27 | $addition: green; 28 | $modification: yellow; 29 | $deletion: red; 30 | 31 | $error: brred; 32 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/bindings/node/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = require("../../build/Release/tree_sitter_syncat_stylesheet_binding"); 3 | } catch (error1) { 4 | if (error1.code !== 'MODULE_NOT_FOUND') { 5 | throw error1; 6 | } 7 | try { 8 | module.exports = require("../../build/Debug/tree_sitter_syncat_stylesheet_binding"); 9 | } catch (error2) { 10 | if (error2.code !== 'MODULE_NOT_FOUND') { 11 | throw error2; 12 | } 13 | throw error1 14 | } 15 | } 16 | 17 | try { 18 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 19 | } catch (_) {} 20 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/direct-child-specifier: -------------------------------------------------------------------------------- 1 | ====================== 2 | Direct child specifier 3 | ====================== 4 | 5 | function_item > "fn", 6 | function_item > identifier, 7 | function_item > arguments identifier {} 8 | 9 | --- 10 | 11 | (stylesheet 12 | (rule 13 | (selectors 14 | (selector (node (kind (name))) (node_modifier (direct)) (node (token (string)))) 15 | (selector (node (kind (name))) (node_modifier (direct)) (node (kind (name)))) 16 | (selector (node (kind (name))) (node_modifier (direct)) (node (kind (name))) (node (kind (name))))) 17 | (styles))) 18 | -------------------------------------------------------------------------------- /syncat/config/style/active/typescript.syncat: -------------------------------------------------------------------------------- 1 | import "./javascript.syncat"; 2 | 3 | function_signature > identifier, 4 | { 5 | color: $function; 6 | } 7 | 8 | type_annotation > ":", 9 | function_type > formal_parameters > "(", 10 | function_type > formal_parameters > ")", 11 | { 12 | color: $operator; 13 | } 14 | 15 | function_type > formal_parameters identifier { 16 | color: $name; 17 | } 18 | 19 | type_identifier, 20 | predefined_type { 21 | color: $type; 22 | } 23 | 24 | "enum", "type" { 25 | color: $keyword; 26 | } 27 | 28 | enum_body > property_identifier, 29 | enum_body > enum_assignment > property_identifier { 30 | color: $value; 31 | } 32 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: foxfriends 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # nvm 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-syncat-stylesheet", 3 | "version": "2.2.1", 4 | "description": "Parser for Syncat stylesheets", 5 | "main": "bindings/node", 6 | "scripts": { 7 | "start": "tree-sitter generate", 8 | "test": "tree-sitter test" 9 | }, 10 | "author": "Cameron Eldridge", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/foxfriends/syncat.git", 14 | "directory": "tree-sitter-syncat-stylesheet" 15 | }, 16 | "license": "ISC", 17 | "devDependencies": { 18 | "tree-sitter-cli": "^0.20.0" 19 | }, 20 | "dependencies": { 21 | "nan": "^2.14.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/style.rs: -------------------------------------------------------------------------------- 1 | use super::{Value, helper::*}; 2 | use tree_sitter::TreeCursor; 3 | 4 | #[derive(Clone, Debug)] 5 | pub(crate) struct Style { 6 | pub(crate) name: String, 7 | pub(crate) value: Value, 8 | } 9 | 10 | impl FromSource for Style { 11 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 12 | children!(tree, "style"); 13 | extras!(tree, "style"); 14 | let name = text!(tree, source, "name")?.to_string(); 15 | tree.goto_next_sibling(); 16 | let value = Value::from_source(tree, source)?; 17 | tree.goto_parent(); 18 | Ok(Style { name, value }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/import.rs: -------------------------------------------------------------------------------- 1 | use super::helper::*; 2 | use enquote::unquote; 3 | use std::path::{Path, PathBuf}; 4 | use tree_sitter::TreeCursor; 5 | 6 | #[derive(Clone, Debug)] 7 | pub(crate) struct Import { 8 | pub(crate) path: PathBuf, 9 | } 10 | 11 | impl AsRef for Import { 12 | fn as_ref(&self) -> &Path { 13 | self.path.as_ref() 14 | } 15 | } 16 | 17 | impl FromSource for Import { 18 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 19 | children!(tree, "import"); 20 | let path = unquote(text!(tree, source, "string")?)?.into(); 21 | tree.goto_parent(); 22 | Ok(Import { path }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /syncat/config/style/active/.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | line_ending { 4 | color: $comment; 5 | dim: true; 6 | content: "¬"; 7 | } 8 | 9 | line_number { 10 | color: $comment; 11 | } 12 | 13 | margin { 14 | color: $comment; 15 | content: unicode; 16 | } 17 | 18 | title { 19 | bold: true; 20 | color: $text; 21 | } 22 | 23 | vcs_addition { 24 | color: $addition; 25 | content: "+"; 26 | } 27 | 28 | vcs_modification { 29 | color: $modification; 30 | content: "~"; 31 | } 32 | 33 | vcs_deletion_above, vcs_deletion_below { 34 | color: $deletion; 35 | } 36 | 37 | vcs_deletion_above { 38 | content: "‾"; 39 | } 40 | 41 | vcs_deletion_below { 42 | content: "_"; 43 | } 44 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod helper; 3 | mod color; 4 | mod declaration; 5 | mod import; 6 | mod node; 7 | mod node_kind; 8 | mod node_modifier; 9 | mod rule; 10 | mod selector; 11 | mod style; 12 | mod stylesheet; 13 | mod value; 14 | mod variable; 15 | 16 | pub use color::Color; 17 | pub(crate) use declaration::Declaration; 18 | pub(crate) use import::Import; 19 | pub(crate) use node::Node; 20 | pub(crate) use node_kind::NodeKind; 21 | pub(crate) use node_modifier::NodeModifier; 22 | pub(crate) use rule::Rule; 23 | pub(crate) use selector::Selector; 24 | pub(crate) use style::Style; 25 | pub use stylesheet::Stylesheet; 26 | pub(crate) use value::Value; 27 | pub(crate) use variable::Variable; 28 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-syncat-stylesheet" 3 | description = "syncat-stylesheet grammar for the tree-sitter parsing library" 4 | version = "0.0.1" 5 | keywords = ["incremental", "parsing", "syncat-stylesheet"] 6 | categories = ["parsing", "text-editors"] 7 | repository = "https://github.com/tree-sitter/tree-sitter-syncat-stylesheet" 8 | edition = "2024" 9 | license = "MIT" 10 | 11 | build = "bindings/rust/build.rs" 12 | include = [ 13 | "bindings/rust/*", 14 | "grammar.js", 15 | "queries/*", 16 | "src/*", 17 | ] 18 | 19 | [lib] 20 | path = "bindings/rust/lib.rs" 21 | 22 | [dependencies] 23 | tree-sitter = "~0.20.0" 24 | 25 | [build-dependencies] 26 | cc = "1.0" 27 | -------------------------------------------------------------------------------- /syncat/src/filter/squeeze_blank_lines.rs: -------------------------------------------------------------------------------- 1 | use crate::Opts; 2 | use crate::line::Line; 3 | 4 | pub fn squeeze_blank_lines(&Opts { squeeze, .. }: &Opts, source: Vec) -> Vec { 5 | if squeeze { 6 | source 7 | .into_iter() 8 | .scan(false, |was_blank, line| { 9 | if line.is_empty() { 10 | let output = if *was_blank { None } else { Some(line) }; 11 | *was_blank = true; 12 | Some(output) 13 | } else { 14 | *was_blank = false; 15 | Some(Some(line)) 16 | } 17 | }) 18 | .flatten() 19 | .collect() 20 | } else { 21 | source 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /syncat/config/style/active/markdown.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | link_label { color: $name; } 4 | link_destination { color: $meta; } 5 | 6 | atx_heading { 7 | bold: true; 8 | } 9 | 10 | atx_heading_marker { 11 | color: $name; 12 | } 13 | 14 | heading_content text { 15 | color: $name; 16 | } 17 | 18 | fenced_code_block (info_string ( text)) + code_fence_content { 19 | language: $language; 20 | } 21 | 22 | fenced_code_block { 23 | color: $meta; 24 | } 25 | 26 | list_marker { 27 | color: $name; 28 | dim: true; 29 | } 30 | 31 | code_span { 32 | color: $string; 33 | } 34 | 35 | link_text { color: $string; } 36 | link { color: $keyword; } 37 | 38 | emphasis { italic: true; } 39 | strong_emphasis { bold: true; } 40 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-syncat-stylesheet", 3 | "version": "2.2.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "nan": { 8 | "version": "2.14.0", 9 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 10 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 11 | }, 12 | "tree-sitter-cli": { 13 | "version": "0.20.0", 14 | "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.0.tgz", 15 | "integrity": "sha512-4D1qapWbJXZ5rrSUGM5rcw5Vuq/smzn9KbiFRhlON6KeuuXjra+KAtDYVrDgAoLIG4ku+jbEEGrJxCptUGi3dg==", 16 | "dev": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /syncat-stylesheet/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "syncat-stylesheet", 3 | "version": "2.2.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "nan": { 8 | "version": "2.14.2", 9 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", 10 | "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" 11 | }, 12 | "tree-sitter-syncat-stylesheet": { 13 | "version": "2.2.1", 14 | "resolved": "https://registry.npmjs.org/tree-sitter-syncat-stylesheet/-/tree-sitter-syncat-stylesheet-2.2.1.tgz", 15 | "integrity": "sha512-9KjCzd7JB+S0fbx7p1Q1LkYpJ0at2YBgt0IGolxVb0k9PSE1TNhE5JeuDtdGjJSTaoBy8vNhzNG3FdStLAO4NQ==", 16 | "requires": { 17 | "nan": "^2.14.0" 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /syncat/config/style/active/html.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | doctype { 4 | color: $meta; 5 | } 6 | 7 | start_tag > "<", start_tag > ">", 8 | self_closing_tag > "<", self_closing_tag > "/>", 9 | end_tag > " ">", 10 | attribute > "=" { 11 | color: $operator; 12 | } 13 | 14 | tag_name { 15 | color: $name; 16 | } 17 | 18 | attribute_name { 19 | color: $value; 20 | } 21 | 22 | quoted_attribute_value, 23 | attribute_value { 24 | color: $string; 25 | } 26 | 27 | comment { 28 | color: $comment; 29 | } 30 | 31 | element (start_tag (tag_name & "code") ~ attribute (attribute_name & "language") + ( attribute_value)) + text { 32 | language: $language-name; 33 | } 34 | 35 | style_element raw_text { 36 | language: css; 37 | } 38 | 39 | script_element raw_text { 40 | language: js; 41 | } 42 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/corpus/style-types: -------------------------------------------------------------------------------- 1 | =========== 2 | Style types 3 | =========== 4 | 5 | styles { 6 | boolean-t: true; 7 | boolean-f: false; 8 | string: "hello"; 9 | name: hello; 10 | color-named: red; 11 | color-hex: #fbb200; 12 | number: 3; 13 | variable: $hello; 14 | capture: $3; 15 | } 16 | --- 17 | 18 | (stylesheet 19 | (rule 20 | (selectors (selector (node (kind (name))))) 21 | (styles 22 | (style (name) (value (boolean))) 23 | (style (name) (value (boolean))) 24 | (style (name) (value (string))) 25 | (style (name) (value (name))) 26 | (style (name) (value (color (named_color)))) 27 | (style (name) (value (color (hex_color)))) 28 | (style (name) (value (number))) 29 | (style (name) (value (variable))) 30 | (style (name) (value (capture)))))) 31 | -------------------------------------------------------------------------------- /syncat/config/style/active/hcl.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | block > identifier { 4 | color: $keyword; 5 | } 6 | 7 | attribute > identifier { 8 | color: $meta; 9 | } 10 | 11 | comment { 12 | color: $comment; 13 | } 14 | 15 | variable_expr > identifier & "var", 16 | variable_expr > identifier & "local", 17 | variable_expr > identifier & "module", 18 | variable_expr > identifier & "data", 19 | variable_expr > identifier & "path", 20 | { 21 | color: $name; 22 | } 23 | 24 | function_call > identifier { 25 | color: $function; 26 | } 27 | 28 | attribute > "=" { 29 | color: $operator; 30 | } 31 | 32 | null_lit, 33 | bool_lit, 34 | numeric_lit { 35 | color: $value; 36 | } 37 | 38 | template_interpolation_start, 39 | template_interpolation_end { 40 | color: $interpolation; 41 | } 42 | 43 | quoted_template_start, 44 | quoted_template_end, 45 | template_literal, 46 | string_lit { 47 | color: $string; 48 | } 49 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/node.rs: -------------------------------------------------------------------------------- 1 | use super::{NodeKind, NodeModifier, helper::*}; 2 | use tree_sitter::TreeCursor; 3 | 4 | #[derive(Clone, Debug)] 5 | pub(crate) struct Node { 6 | pub(crate) kind: NodeKind, 7 | pub(crate) modifier: NodeModifier, 8 | } 9 | 10 | impl Node { 11 | pub(crate) fn can_try_again(&self) -> bool { 12 | match self.modifier { 13 | NodeModifier::Child => true, 14 | NodeModifier::DirectChild => false, 15 | NodeModifier::Sibling => true, 16 | NodeModifier::DirectSibling => false, 17 | NodeModifier::Also => false, 18 | } 19 | } 20 | } 21 | 22 | impl FromSource for Node { 23 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 24 | let kind = NodeKind::from_source(tree, source)?; 25 | Ok(Node { 26 | kind, 27 | modifier: NodeModifier::default(), 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /syncat/config/style/active/jsx.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | jsx_opening_element > "<", 4 | jsx_opening_element > ">", 5 | jsx_closing_element > "<", 6 | jsx_closing_element > "/", 7 | jsx_opening_element > "<", 8 | jsx_self_closing_element > "<", 9 | jsx_self_closing_element > "/", 10 | jsx_self_closing_element > ">" { 11 | color: $operator; 12 | } 13 | 14 | jsx_opening_element > identifier & /^[a-z]/, 15 | jsx_closing_element > identifier & /^[a-z]/, 16 | jsx_self_closing_element > identifier & /^[a-z]/ { 17 | color: $name; 18 | } 19 | 20 | jsx_opening_element > identifier & /^[A-Z]/, 21 | jsx_closing_element > identifier & /^[A-Z]/, 22 | jsx_self_closing_element > identifier & /^[A-Z]/ { 23 | color: $type; 24 | } 25 | 26 | jsx_expression > "{", 27 | jsx_expression > "}" { 28 | color: $interpolation; 29 | } 30 | 31 | jsx_attribute property_identifier { 32 | color: $value; 33 | } 34 | 35 | jsx_text { 36 | color: $string; 37 | } 38 | -------------------------------------------------------------------------------- /syncat/config/style/active/css.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | "@import", 4 | "@keyframes" { 5 | color: $keyword; 6 | } 7 | 8 | function_name { 9 | color: $builtin; 10 | } 11 | 12 | import_statement plain_value, 13 | string_value { 14 | color: $string; 15 | } 16 | 17 | color_value, 18 | float_value, 19 | integer_value, 20 | plain_value { 21 | color: $value; 22 | } 23 | 24 | property_name & /^\-\-/, 25 | call_expression (function_name "var") + arguments plain_value & /^\-\-/ { 26 | color: $variable; 27 | } 28 | 29 | pseudo_class_selector > ":", 30 | pseudo_class_selector > class_name { 31 | color: $keyword; 32 | } 33 | 34 | property_name { 35 | color: $function; 36 | } 37 | 38 | tag_name { color: $name; } 39 | class_selector { color: $type; } 40 | id_selector { color: $function; } 41 | 42 | comment { 43 | color: $comment; 44 | } 45 | 46 | media_statement "@media" { 47 | color: $keyword; 48 | } 49 | 50 | feature_name { 51 | color: $function; 52 | } 53 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/node_modifier.rs: -------------------------------------------------------------------------------- 1 | use super::helper::*; 2 | use tree_sitter::TreeCursor; 3 | 4 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 5 | pub(crate) enum NodeModifier { 6 | Child, 7 | DirectChild, 8 | DirectSibling, 9 | Sibling, 10 | Also, 11 | } 12 | 13 | impl Default for NodeModifier { 14 | fn default() -> Self { 15 | Self::Child 16 | } 17 | } 18 | 19 | impl FromSource for NodeModifier { 20 | fn from_source(tree: &mut TreeCursor, _source: &[u8]) -> crate::Result { 21 | children!(tree, "node_modifier"); 22 | let modifier = match tree.node().kind() { 23 | "direct" => Self::DirectChild, 24 | "direct_sibling" => Self::DirectSibling, 25 | "sibling" => Self::Sibling, 26 | "also" => Self::Also, 27 | name => return Err(crate::Error::invalid("node_modifier", name)), 28 | }; 29 | tree.goto_parent(); 30 | Ok(modifier) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - uses: actions/cache@v2 16 | with: 17 | path: | 18 | ~/.cargo/registry 19 | ~/.cargo/git 20 | target 21 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 22 | - name: Install Rust nightly 23 | run: | 24 | rustup toolchain update --no-self-update stable 25 | rustup default stable 26 | - name: Build 27 | run: cargo build --release 28 | - name: Release 29 | uses: actions/create-release@v1 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | with: 33 | tag_name: ${{ github.ref }} 34 | release_name: Release ${{ github.ref }} 35 | draft: false 36 | prerelease: false 37 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/bindings/node/binding.cc: -------------------------------------------------------------------------------- 1 | #include "tree_sitter/parser.h" 2 | #include 3 | #include "nan.h" 4 | 5 | using namespace v8; 6 | 7 | extern "C" TSLanguage * tree_sitter_syncat_stylesheet(); 8 | 9 | namespace { 10 | 11 | NAN_METHOD(New) {} 12 | 13 | void Init(Local exports, Local module) { 14 | Local tpl = Nan::New(New); 15 | tpl->SetClassName(Nan::New("Language").ToLocalChecked()); 16 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 17 | 18 | Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); 19 | Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); 20 | Nan::SetInternalFieldPointer(instance, 0, tree_sitter_syncat_stylesheet()); 21 | 22 | Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("syncat_stylesheet").ToLocalChecked()); 23 | Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); 24 | } 25 | 26 | NODE_MODULE(tree_sitter_syncat_stylesheet_binding, Init) 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/stylesheet/matches.rs: -------------------------------------------------------------------------------- 1 | use regex::Captures; 2 | use std::collections::BTreeMap; 3 | 4 | #[derive(Default, Debug)] 5 | pub(crate) struct Matches<'k, 's> { 6 | matches: BTreeMap<&'k str, &'s str>, 7 | captures: Vec>, 8 | } 9 | 10 | impl<'k, 's> Matches<'k, 's> { 11 | pub(crate) fn get(&self, key: &str) -> Option<&str> { 12 | self.matches.get(key).copied() 13 | } 14 | 15 | pub(crate) fn capture(&self, index: usize) -> Option<&str> { 16 | self.captures 17 | .iter() 18 | .flat_map(|captures| captures.iter()) 19 | .nth(index) 20 | .flatten() 21 | .map(|m| m.as_str()) 22 | } 23 | 24 | pub(crate) fn insert(&mut self, key: &'k str, value: &'s str) { 25 | self.matches.insert(key, value); 26 | } 27 | 28 | pub(crate) fn push(&mut self, captures: Captures<'s>) { 29 | self.captures.push(captures); 30 | } 31 | 32 | pub(crate) fn merge(&mut self, mut other: Self) { 33 | self.matches.append(&mut other.matches); 34 | self.captures.append(&mut other.captures); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Cameron Eldridge 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /syncat/src/colorize/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::too_many_arguments)] 2 | 3 | use crate::config::Config; 4 | use crate::language::LangMap; 5 | use std::fmt::{self, Debug, Display, Formatter}; 6 | use syncat_stylesheet::Stylesheet; 7 | use tree_sitter::Tree; 8 | 9 | mod sexp; 10 | mod source; 11 | 12 | pub(super) struct Colorizer<'a> { 13 | pub source: &'a str, 14 | pub tree: Tree, 15 | pub config: &'a Config, 16 | pub stylesheet: Stylesheet, 17 | pub lang_map: &'a LangMap, 18 | } 19 | 20 | impl Display for Colorizer<'_> { 21 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 22 | source::write( 23 | f, 24 | self.source, 25 | &self.tree, 26 | self.config, 27 | &self.stylesheet, 28 | self.lang_map, 29 | ) 30 | } 31 | } 32 | 33 | impl Debug for Colorizer<'_> { 34 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 35 | sexp::write( 36 | f, 37 | self.source, 38 | &self.tree, 39 | self.config, 40 | &self.stylesheet, 41 | self.lang_map, 42 | ) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/declaration.rs: -------------------------------------------------------------------------------- 1 | use super::{Value, Variable, helper::*}; 2 | use std::collections::BTreeMap; 3 | use std::iter::FromIterator; 4 | use tree_sitter::TreeCursor; 5 | 6 | #[derive(Clone, Debug)] 7 | pub(crate) struct Declaration { 8 | pub(crate) variable: Variable, 9 | pub(crate) value: Value, 10 | } 11 | 12 | impl FromSource for Declaration { 13 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 14 | children!(tree, "declaration"); 15 | 16 | let variable = Variable::from_source(tree, source)?; 17 | tree.goto_next_sibling(); 18 | let value = Value::from_source(tree, source)?; 19 | 20 | tree.goto_parent(); 21 | Ok(Declaration { variable, value }) 22 | } 23 | } 24 | 25 | impl FromIterator for BTreeMap { 26 | fn from_iter>(iter: I) -> Self { 27 | iter.into_iter().fold( 28 | Self::default(), 29 | |mut map, Declaration { variable, value }| { 30 | map.insert(variable.name().to_owned(), value); 31 | map 32 | }, 33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /syncat/config/style/active/graphql.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | operation_type, 4 | fragment_definition "fragment", 5 | interface_type_definition "interface", 6 | object_type_definition "type", 7 | union_type_definition "union", 8 | type_condition "on", 9 | implements_interfaces "implements", 10 | "=", "|", "!", "...", { 11 | color: $keyword; 12 | } 13 | 14 | type_condition > named_type, 15 | interface_type_definition > name, 16 | object_type_definition > name, 17 | union_type_definition > name { 18 | color: $type; 19 | } 20 | 21 | operation_definition > name, 22 | field > name { 23 | color: $function; 24 | } 25 | 26 | variable { 27 | color: $variable; 28 | } 29 | 30 | int_value, float_value, boolean_value { 31 | color: $constant; 32 | } 33 | 34 | string_value { 35 | color: $string; 36 | } 37 | 38 | object_field > name { 39 | color: $variable; 40 | } 41 | 42 | named_type name & "Int", 43 | named_type name & "String", 44 | named_type name & "Boolean", 45 | named_type name & "Float", 46 | named_type name & "ID" { 47 | color: $builtin; 48 | } 49 | 50 | named_type name { 51 | color: $type; 52 | } 53 | 54 | fragment_name { 55 | color: $type; 56 | } 57 | 58 | comment { 59 | color: $comment; 60 | } 61 | -------------------------------------------------------------------------------- /syncat/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | description = "Syntax aware cat" 3 | repository = "https://github.com/foxfriends/syncat" 4 | keywords = ["cli", "syntax", "cat", "highlighting"] 5 | readme = "../README.md" 6 | license = "MIT" 7 | homepage = "https://github.com/foxfriends/syncat" 8 | authors = ["Cameron Eldridge "] 9 | edition = "2024" 10 | name = "syncat" 11 | version = "3.8.4" 12 | categories = ["command-line-utilities"] 13 | 14 | [features] 15 | default = [] 16 | vendored-openssl = ["git2/vendored-openssl"] 17 | vendored-libgit2 = ["git2/vendored-libgit2"] 18 | 19 | [dependencies] 20 | ansi_term = "0.12.1" 21 | directories = "2.0.2" 22 | git2 = "0.16.1" 23 | hex = "0.4.2" 24 | lazy_static = "1.4.0" 25 | regex = "1.5.5" 26 | terminal_size = "0.1.10" 27 | tree-sitter = "0.25.3" 28 | console = "0.10.0" 29 | syncat-stylesheet = { version = "3.5.0", features = ["ansi_term"] } 30 | # syncat-stylesheet = { path = "../syncat-stylesheet/", features = ["ansi_term"] } 31 | toml = "0.5.6" 32 | libloading = "0.5.2" 33 | cc = "1.0.50" 34 | serde = { version = "1.0.105", features = ["derive"] } 35 | tempdir = "0.3.7" 36 | clap = { version = "4.4.6", features = ["derive"] } 37 | tar = "0.4.40" 38 | 39 | [build-dependencies] 40 | tar = "0.4.40" 41 | -------------------------------------------------------------------------------- /syncat/config/style/active/haskell.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | "module", "import", "hiding", "qualified", "as", "where", 4 | "let", "in", "type", "newtype", "data", "deriving", "class", "instance", 5 | "case", "of", "otherwise", "do", "if", "then", "else" 6 | { 7 | color: $keyword; 8 | } 9 | 10 | "return", "pure", "fmap", "print", "putStrLn", "show", "read", "getLine", "getChar", "putChar" { 11 | color: $builtin; 12 | } 13 | 14 | variable_symbol, wildcard, "->", "=", "=>", annotation, "<-", lambda_head "\\", "::" 15 | { 16 | color: $operator; 17 | } 18 | 19 | module_identifier { 20 | color: $name; 21 | } 22 | 23 | function_declaration > !* + variable_identifier, 24 | function_application > !* + variable_identifier, 25 | type_signature > variable_identifier, 26 | signature > variable, { 27 | color: $function; 28 | } 29 | 30 | type_variable_identifier { color: $variable; } 31 | type_class_identifier { color: $type; } 32 | 33 | type_constructor_identifier, 34 | constructor_identifier, 35 | type, 36 | { 37 | color: $type; 38 | } 39 | 40 | unit_constructor, list_expression > "[", list_expression > "]" { color: $keyword; } 41 | string { color: $string; } 42 | integer, float, char { color: $value; } 43 | comment { color: $comment; } 44 | -------------------------------------------------------------------------------- /syncat/config/style/active/sql.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | /^set$/i, 4 | /^to$/i, 5 | /^select$/i, 6 | /^exists$/i, 7 | /^from$/i, 8 | /^where$/i, 9 | /^with$/i, 10 | /^as$/i, 11 | /^in$/i, 12 | /^is$/i, 13 | /^and$/i, 14 | /^or$/i, 15 | /^on$/i, 16 | /^union$/i, 17 | /^all$/i, 18 | /^default$/i, 19 | /^null$/i, 20 | /^create$/i, 21 | /^view$/i, 22 | /^table$/i, 23 | /^if$/i, 24 | /^not$/i, 25 | /^truncate$/i, 26 | /^group$/i, 27 | /^by$/i, 28 | /^having$/i, 29 | /^order$/i, 30 | /^asc$/i, 31 | /^desc$/i, 32 | /^inner$/i, 33 | /^outer$/i, 34 | /^left$/i, 35 | /^right$/i, 36 | /^cross$/i, 37 | /^lateral$/i, 38 | /^join$/i, 39 | /^except$/i, 40 | /^recursive$/i, 41 | /^insert$/i, 42 | /^into$/i, 43 | /^returning$/i, 44 | /^values$/i, 45 | select_statement >, 46 | create_view_statement >, 47 | { 48 | color: $keyword; 49 | } 50 | 51 | type { 52 | color: $type; 53 | } 54 | 55 | comment { 56 | color: $comment; 57 | } 58 | 59 | function_call > identifier { 60 | color: $function; 61 | } 62 | 63 | number { color: $value; } 64 | string { color: $string; } 65 | identifier { color: $variable; } 66 | 67 | pg_command { color: $builtin; } 68 | asterisk_expression { color: $operator; } 69 | 70 | "<>", "+", "*", "-", "/", "=", "<=", "<", ">=", ">" { 71 | color: $operator; 72 | } 73 | -------------------------------------------------------------------------------- /syncat/config/style/active/regex.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | pattern_character { 4 | color: $string; 5 | } 6 | 7 | boundary_assertion, 8 | non_boundary_assertion, 9 | control_escape, 10 | control_letter_escape, 11 | identity_escape { 12 | color: $builtin; 13 | } 14 | 15 | optional, 16 | zero_or_more, 17 | one_or_more, 18 | count_quantifier > "{", 19 | count_quantifier > "}", 20 | count_quantifier > ",", 21 | start_assertion, 22 | end_assertion, 23 | character_class > "[", 24 | character_class > "[" + "^", 25 | character_class > "]", 26 | disjunction > "|", 27 | class_range > "-" { 28 | color: $keyword; 29 | } 30 | 31 | lookahead_assertion > "(?", 32 | lookahead_assertion > "=", 33 | lookahead_assertion > "!", 34 | lookahead_assertion > "<=", 35 | lookahead_assertion > " ")", 37 | non_capturing_group > "(?:", 38 | non_capturing_group > ")", 39 | anonymous_capturing_group > "(", 40 | anonymous_capturing_group > ")", 41 | named_capturing_group > "(?<", 42 | named_capturing_group > ">", 43 | named_capturing_group > ")" { 44 | color: $function; 45 | } 46 | 47 | backreference_escape, 48 | group_name { 49 | color: $name; 50 | } 51 | 52 | any_character, 53 | character_class_escape, 54 | decimal_digits, 55 | class_character { 56 | color: $value; 57 | } 58 | -------------------------------------------------------------------------------- /syncat/config/style/active/bash.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | function_definition > word, 4 | command_name { 5 | color: $function; 6 | } 7 | 8 | "&&", "||", "&", "|", 9 | "!", "!=", "==", "<", ">", "<=", ">=", 10 | test_operator { 11 | color: $operator; 12 | } 13 | 14 | "export", 15 | "return", "exit", "function", 16 | "if", "then", "elif", "else", "fi", 17 | "case", "in", "esac", 18 | "for", "while", "do", "done", 19 | test_command > "[", 20 | test_command > "]", 21 | test_command > "[[", 22 | test_command > "]]", 23 | test_command > "((", 24 | test_command > "))" { 25 | color: $keyword; 26 | } 27 | 28 | case_item > word { 29 | color: $type; 30 | } 31 | 32 | case_item > ")", 33 | case_item > ";;" { 34 | color: $keyword; 35 | } 36 | 37 | word /^\d+$/ { 38 | color: $value; 39 | } 40 | 41 | raw_string, 42 | string > { 43 | color: $string; 44 | } 45 | 46 | variable_name, 47 | expansion > "${", 48 | expansion > "}", 49 | simple_expansion, { 50 | color: $variable; 51 | } 52 | 53 | command_substitution > "$(", 54 | command_substitution > ")" { 55 | color: $interpolation; 56 | } 57 | 58 | comment { 59 | color: $comment; 60 | } 61 | 62 | command (command_name) ~ word & /^-/ { 63 | color: $constant; 64 | } 65 | 66 | command_name ".", 67 | command_name "cd", 68 | command_name "alias" { 69 | color: $builtin; 70 | } 71 | -------------------------------------------------------------------------------- /syncat/config/style/active/paper.syncat: -------------------------------------------------------------------------------- 1 | shadow { 2 | background-color: brblack; 3 | } 4 | 5 | li "prefix", 6 | blockquote "prefix" { 7 | color: brblack; 8 | dim: true; 9 | } 10 | 11 | rule { 12 | color: black; 13 | } 14 | 15 | strong { 16 | bold: true; 17 | } 18 | 19 | emphasis { 20 | italic: true; 21 | } 22 | 23 | strikethrough { 24 | strikethrough: true; 25 | } 26 | 27 | link { 28 | underline: true; 29 | } 30 | 31 | caption { 32 | underline: true; 33 | } 34 | 35 | h1 { 36 | bold: true; 37 | } 38 | 39 | h2 { 40 | bold: true; 41 | } 42 | 43 | h3 { 44 | bold: true; 45 | underline: true; 46 | } 47 | 48 | h4 { 49 | bold: true; 50 | underline: true; 51 | dim: true; 52 | } 53 | 54 | h5 { 55 | underline: true; 56 | } 57 | 58 | h6 { 59 | underline: true; 60 | dim: true; 61 | } 62 | 63 | code { 64 | background-color: #9ba2af; 65 | color: black; 66 | } 67 | 68 | footnote-def, footnote-ref { 69 | color: brblack; 70 | dim: true; 71 | } 72 | 73 | codeblock txt, 74 | codeblock txt "prefix", 75 | codeblock txt "suffix", 76 | codeblock txt "lang-tag", { 77 | background-color: #9ba2af; 78 | color: black; 79 | } 80 | 81 | codeblock *, 82 | codeblock * "prefix", 83 | codeblock * "suffix", { 84 | background-color: black; 85 | color: white; 86 | } 87 | 88 | codeblock * "lang-tag" { 89 | color: white; 90 | dim: true; 91 | } 92 | 93 | paper { 94 | background-color: white; 95 | color: black; 96 | } 97 | -------------------------------------------------------------------------------- /syncat/config/style/active/scala.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | package_identifier, 4 | import_declaration identifier, 5 | object_definition > identifier, 6 | class_definition > identifier, 7 | type_identifier, 8 | instance_expression > call_expression > identifier, 9 | field_expression > identifier & /^[A-Z].*/, 10 | type_parameters > identifier, 11 | { 12 | color: $type; 13 | } 14 | 15 | package_clause "package", 16 | import_declaration "import", 17 | object_definition "object", 18 | class_definition "case", 19 | class_definition "class", 20 | wildcard, 21 | function_definition "def", 22 | function_definition "=", 23 | val_definition "val", 24 | class_parameter "val", 25 | var_definition "var", 26 | class_parameter "var", 27 | operator_identifier, 28 | instance_expression "new", 29 | "=>", 30 | call_expression "for", 31 | infix_expression "until", 32 | infix_expression "to", 33 | { 34 | color: $keyword; 35 | } 36 | 37 | function_definition > identifier, 38 | call_expression > identifier, 39 | call_expression > field_expression identifier + identifier, 40 | infix_expression > identifier, 41 | field_expression identifier + identifier & /^to[A-Z].*/, 42 | { 43 | color: $function; 44 | } 45 | 46 | number { 47 | color: $value; 48 | } 49 | 50 | string_transform_expression > identifier, 51 | string { 52 | color: $string; 53 | } 54 | 55 | string interpolation { 56 | color: $interpolation; 57 | } 58 | 59 | comment { 60 | color: $comment; 61 | } 62 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/helper.rs: -------------------------------------------------------------------------------- 1 | use tree_sitter::TreeCursor; 2 | 3 | macro_rules! extras { 4 | ($tree:ident, $context:literal) => { 5 | while $tree.node().is_extra() || !$tree.node().is_named() { 6 | if !$tree.goto_next_sibling() { 7 | return Err($crate::Error::invalid( 8 | concat!("extras(", $context, ")"), 9 | "no more children", 10 | )); 11 | } 12 | } 13 | }; 14 | } 15 | 16 | #[macro_export] 17 | macro_rules! children { 18 | ($tree:ident, $name:literal) => {{ 19 | extras!($tree, $name); 20 | match $tree.node().kind() { 21 | $name => $tree.goto_first_child(), 22 | name => { 23 | return Err($crate::Error::invalid( 24 | concat!("children(", $name, ")"), 25 | name, 26 | )); 27 | } 28 | } 29 | }}; 30 | } 31 | 32 | #[macro_export] 33 | macro_rules! text { 34 | ($tree:ident, $source:expr, $name:literal) => {{ 35 | extras!($tree, $name); 36 | match $tree.node().kind() { 37 | $name => $tree.node().utf8_text($source), 38 | name => return Err($crate::Error::invalid(concat!("text(", $name, ")"), name)), 39 | } 40 | }}; 41 | } 42 | 43 | pub(super) trait FromSource: Sized { 44 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> Result; 45 | } 46 | -------------------------------------------------------------------------------- /syncat/config/style/active/swift.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | attribute { 4 | color: $meta; 5 | dim: true; 6 | } 7 | 8 | type_identifier, 9 | call_expression > simple_identifier & /[A-Z].*/, 10 | { 11 | color: $type; 12 | } 13 | 14 | "import", 15 | "class", 16 | "struct", 17 | "enum", 18 | "extension", 19 | "protocol", 20 | "var", 21 | "let", 22 | "func", 23 | "guard", 24 | "if", 25 | "else", 26 | "switch", 27 | "case", 28 | "in", 29 | "unowned", 30 | "weak", 31 | for_statement > "for", 32 | "while", 33 | "do", 34 | { 35 | color: $keyword; 36 | } 37 | 38 | "==", "!=", "<", ">", "<=", ">=", 39 | "!", "&&", "||", 40 | "+", "-", "*", "/", "|", "&", "^", "~", "%", 41 | "=", "+=", "-=", "*=", "/=", "|=", "&=", "^=", "%=", "++", "--", 42 | "->", "...", "?", "??", "\\", "_" { 43 | color: $operator; 44 | } 45 | 46 | parameter > simple_identifier + simple_identifier, 47 | class_body > property_declaration > pattern > simple_identifier { 48 | color: $variable; 49 | } 50 | 51 | call_expression > simple_identifier, 52 | function_declaration > simple_identifier, 53 | parameter > simple_identifier, 54 | { 55 | color: $function; 56 | } 57 | 58 | integer_literal, 59 | real_literal, 60 | "nil", true, false { 61 | color: $value; 62 | } 63 | 64 | line_string_literal > "\\(", 65 | line_string_literal > ")" { 66 | color: $interpolation; 67 | } 68 | 69 | "self" { 70 | color: $name; 71 | } 72 | 73 | line_string_literal { 74 | color: $string; 75 | } 76 | 77 | comment { 78 | color: $comment; 79 | } 80 | -------------------------------------------------------------------------------- /tree-sitter-syncat-stylesheet/bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.include(&src_dir); 6 | c_config 7 | .flag_if_supported("-Wno-unused-parameter") 8 | .flag_if_supported("-Wno-unused-but-set-variable") 9 | .flag_if_supported("-Wno-trigraphs"); 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | 13 | // If your language uses an external scanner written in C, 14 | // then include this block of code: 15 | 16 | /* 17 | let scanner_path = src_dir.join("scanner.c"); 18 | c_config.file(&scanner_path); 19 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 20 | */ 21 | 22 | c_config.compile("parser"); 23 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 24 | 25 | // If your language uses an external scanner written in C++, 26 | // then include this block of code: 27 | 28 | /* 29 | let mut cpp_config = cc::Build::new(); 30 | cpp_config.cpp(true); 31 | cpp_config.include(&src_dir); 32 | cpp_config 33 | .flag_if_supported("-Wno-unused-parameter") 34 | .flag_if_supported("-Wno-unused-but-set-variable"); 35 | let scanner_path = src_dir.join("scanner.cc"); 36 | cpp_config.file(&scanner_path); 37 | cpp_config.compile("scanner"); 38 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /syncat/config/style/active/c.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | primitive_type, 4 | type_identifier { 5 | color: $type; 6 | } 7 | 8 | preproc_include > /^#/, 9 | preproc_function_def > /^#/, 10 | preproc_def > /^#/, 11 | preproc_directive > /^#/, 12 | preproc_if > /^#/, 13 | preproc_ifdef > /^#/, 14 | preproc_elif > /^#/, 15 | preproc_else > /^#/ { 16 | color: $meta; 17 | dim: true; 18 | } 19 | 20 | type_qualifier, 21 | sized_type_specifier, 22 | storage_class_specifier, 23 | "struct", "enum", "typedef", 24 | "return", "break", "continue", 25 | "if", "else", "for", "while", "do", 26 | "switch", "case", "default", 27 | "sizeof", "static" { 28 | color: $keyword; 29 | } 30 | 31 | preproc_function_def > identifier, 32 | call_expression > identifier, 33 | function_declarator > identifier { 34 | color: $function; 35 | } 36 | 37 | subscript_expression > "[", 38 | subscript_expression > "]", 39 | "==", "!=", "<", ">", "<=", ">=", 40 | "!", "&&", "||", 41 | "+", "-", "*", "/", "|", "&", "^", "~", "%", 42 | "=", "+=", "-=", "*=", "/=", "|=", "&=", "^=", "%=", "++", "--", 43 | "->", "..." { 44 | color: $operator; 45 | } 46 | 47 | preproc_ifdef > identifier, 48 | preproc_def > identifier, 49 | number_literal, 50 | null, true, false { 51 | color: $value; 52 | } 53 | 54 | identifier & /^[A-Z0-9_]+$/ { 55 | color: $constant; 56 | } 57 | 58 | system_lib_string { 59 | color: $builtin; 60 | } 61 | 62 | char_literal, 63 | string_literal { 64 | color: $string; 65 | } 66 | 67 | comment { 68 | color: $comment; 69 | } 70 | -------------------------------------------------------------------------------- /syncat/config/style/active/ruby.syncat: -------------------------------------------------------------------------------- 1 | import "../colours.syncat"; 2 | 3 | "if", "then", "elsif", "else", "end", 4 | "unless", "until", 5 | "for", "while", "do", 6 | "break", "continue", "return", "yield", 7 | "when", "case", 8 | "module", "class", 9 | "include", "def" { 10 | color: $keyword; 11 | } 12 | 13 | "=", "+=", "-=", "*=", "/=", "**=", "<<=", ">>=", "^=", "%=", "&=", "|=", "||=", 14 | "+", "-", "*", "/", "%", "**", "^", "~", "&", "|", "<<", ">>", 15 | "<", ">", "<=", ">=", "==", "!=", "===", "!==", "=~", "!~", "<=>", 16 | "not", "and", "or", "&&", "||", "!", 17 | "..", "...", 18 | element_reference > "[", 19 | element_reference > "]" { 20 | color: $operator; 21 | } 22 | 23 | method > identifier, 24 | call > identifier, 25 | method_call > scope_resolution > identifier, 26 | method_call > identifier { 27 | color: $function; 28 | } 29 | 30 | "defined?" { 31 | color: $builtin; 32 | } 33 | 34 | subshell >, 35 | string > { 36 | color: $string; 37 | } 38 | 39 | symbol, 40 | pair > (symbol) + ":" { 41 | color: $meta; 42 | } 43 | 44 | constant & /^[A-Z][a-zA-Z_]*$/ { 45 | color: $type; 46 | } 47 | 48 | array > "[", array > "]", 49 | hash > "{", hash > "}", 50 | true, false, 51 | integer, 52 | nil { 53 | color: $value; 54 | } 55 | 56 | constant & /^[A-Z_]+$/ { 57 | color: $constant; 58 | } 59 | 60 | interpolation > "#{", 61 | interpolation > "}" { 62 | color: $interpolation; 63 | } 64 | 65 | global_variable, 66 | instance_variable, 67 | "self" { 68 | color: $variable; 69 | } 70 | 71 | comment { 72 | color: $comment; 73 | } 74 | 75 | regex { 76 | language: regex; 77 | } 78 | -------------------------------------------------------------------------------- /syncat-stylesheet/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::ffi::OsString; 3 | use std::fs; 4 | use std::path::Path; 5 | 6 | fn main() { 7 | println!("cargo:rerun-if-changed=./node_modules/tree-sitter-syncat-stylesheet"); 8 | 9 | let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); 10 | let path = Path::new(&manifest_dir).join("./node_modules/tree-sitter-syncat-stylesheet/src"); 11 | let package = "tree-sitter-syncat-stylesheet".to_string(); 12 | 13 | for file in fs::read_dir(&path) 14 | .unwrap_or_else(|_| panic!("Package {} is not found at {:?}", package, path)) 15 | { 16 | // each file is meant to be built individually and linked 17 | let mut build = cc::Build::new(); 18 | if let Ok(file) = file { 19 | if file.path().is_dir() { 20 | continue; 21 | } 22 | if file.path().file_name() == Some(&OsString::from("binding.cc")) { 23 | // we don't want the C++ binding 24 | continue; 25 | } 26 | if file.path().extension() == Some(&OsString::from("c")) { 27 | build.file(file.path()); 28 | } else if file.path().extension() == Some(&OsString::from("cc")) { 29 | build.cpp(true).file(file.path()); 30 | } else { 31 | continue; 32 | } 33 | build.include(&path).warnings(false).compile(&format!( 34 | "{}-{}", 35 | package, 36 | file.path().file_stem().unwrap().to_str().unwrap() 37 | )); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /syncat/build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::fs::{File, read_dir}; 3 | use std::io::Write; 4 | use std::path::Path; 5 | 6 | fn main() -> Result<(), Box> { 7 | let out_dir = env::var("OUT_DIR")?; 8 | let out_path = Path::new(&out_dir).join("targets.rs"); 9 | let mut output = File::create(out_path)?; 10 | writeln!(output, "const HOST: &str = {:?};", env::var("HOST")?)?; 11 | writeln!(output, "const TARGET: &str = {:?};", env::var("TARGET")?)?; 12 | 13 | let out_path = Path::new(&out_dir).join("config.tar"); 14 | let mut output = File::create(out_path)?; 15 | let mut ar = tar::Builder::new(&mut output); 16 | 17 | let manifest_dir = env::var("CARGO_MANIFEST_DIR")?; 18 | let config_dir = Path::new(&manifest_dir).join("config"); 19 | 20 | println!( 21 | "cargo:rerun-if-changed={}", 22 | config_dir.join("languages.toml").display() 23 | ); 24 | println!( 25 | "cargo:rerun-if-changed={}", 26 | config_dir.join("style/colours.syncat").display(), 27 | ); 28 | 29 | ar.append_path_with_name(config_dir.join("languages.toml"), "languages.toml")?; 30 | ar.append_path_with_name( 31 | config_dir.join("style/colours.syncat"), 32 | "style/colours.syncat", 33 | )?; 34 | for entry in read_dir(config_dir.join("style/active"))? { 35 | let entry = entry?; 36 | println!("cargo:rerun-if-changed={}", entry.path().display(),); 37 | ar.append_path_with_name( 38 | entry.path(), 39 | Path::new("style/active").join(entry.file_name()), 40 | )?; 41 | } 42 | ar.into_inner()?; 43 | 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /syncat/src/filter/line_numbers.rs: -------------------------------------------------------------------------------- 1 | use crate::Opts; 2 | use crate::line::Line; 3 | 4 | pub fn line_numbers<'a>( 5 | &Opts { 6 | frame, 7 | numbered_nonblank, 8 | numbered, 9 | .. 10 | }: &Opts, 11 | ) -> impl 'a + FnMut(Vec) -> Vec { 12 | let mut line_number = 0usize; 13 | let mut skip_next = false; 14 | move |source| { 15 | if numbered_nonblank { 16 | source 17 | .into_iter() 18 | .map(|line| { 19 | if skip_next { 20 | skip_next = false; 21 | line 22 | } else if line.is_empty() || skip_next { 23 | line.with_no_number() 24 | } else { 25 | line_number += 1; 26 | if line.no_newline { 27 | skip_next = frame == 0; 28 | } 29 | line.with_number(line_number) 30 | } 31 | }) 32 | .collect() 33 | } else if numbered { 34 | source 35 | .into_iter() 36 | .map(|line| { 37 | if skip_next { 38 | skip_next = false; 39 | line 40 | } else { 41 | line_number += 1; 42 | if line.no_newline { 43 | skip_next = frame == 0; 44 | } 45 | line.with_number(line_number) 46 | } 47 | }) 48 | .collect() 49 | } else { 50 | source 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /syncat/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{self, Display, Formatter}; 2 | use std::path::{Path, PathBuf}; 3 | 4 | #[derive(Debug)] 5 | pub struct Error { 6 | path: Option, 7 | message: String, 8 | source: Option>, 9 | hint: Option, 10 | } 11 | 12 | impl Error { 13 | pub(crate) fn new(message: impl Display) -> Self { 14 | Self { 15 | path: None, 16 | message: message.to_string(), 17 | source: None, 18 | hint: None, 19 | } 20 | } 21 | 22 | pub(crate) fn with_source( 23 | mut self, 24 | source: impl std::error::Error + Sync + Send + 'static, 25 | ) -> Self { 26 | self.source = Some(Box::new(source)); 27 | self 28 | } 29 | 30 | pub(crate) fn with_path(mut self, path: impl AsRef) -> Self { 31 | self.path = Some(path.as_ref().to_owned()); 32 | self 33 | } 34 | 35 | pub(crate) fn with_hint(mut self, hint: impl Display) -> Self { 36 | self.hint = Some(hint.to_string()); 37 | self 38 | } 39 | } 40 | 41 | impl std::error::Error for Error { 42 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 43 | self.source.as_ref().map(|s| &**s as _) 44 | } 45 | } 46 | 47 | impl Display for Error { 48 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 49 | write!(f, "syncat: ")?; 50 | if let Some(path) = &self.path { 51 | write!(f, "{}: ", path.display())?; 52 | } 53 | write!(f, "{}", self.message)?; 54 | if let Some(source) = &self.source { 55 | write!(f, " ({source})")?; 56 | } 57 | if let Some(hint) = &self.hint { 58 | write!(f, "\nhelp: {hint}")?; 59 | } 60 | Ok(()) 61 | } 62 | } 63 | 64 | pub(crate) type Result = std::result::Result; 65 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/color.rs: -------------------------------------------------------------------------------- 1 | use super::helper::*; 2 | use hex::FromHex; 3 | use std::str::FromStr; 4 | use tree_sitter::TreeCursor; 5 | 6 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 7 | pub enum Color { 8 | Red, 9 | Green, 10 | Blue, 11 | Yellow, 12 | Purple, 13 | Cyan, 14 | White, 15 | Black, 16 | BrRed, 17 | BrGreen, 18 | BrBlue, 19 | BrYellow, 20 | BrPurple, 21 | BrCyan, 22 | BrWhite, 23 | BrBlack, 24 | Hex(u32), 25 | } 26 | 27 | impl FromStr for Color { 28 | type Err = crate::Error; 29 | 30 | fn from_str(string: &str) -> Result { 31 | let color = match string { 32 | "red" => Self::Red, 33 | "green" => Self::Green, 34 | "blue" => Self::Blue, 35 | "yellow" => Self::Yellow, 36 | "purple" => Self::Purple, 37 | "cyan" => Self::Cyan, 38 | "white" => Self::White, 39 | "black" => Self::Black, 40 | "brred" => Self::BrRed, 41 | "brgreen" => Self::BrGreen, 42 | "brblue" => Self::BrBlue, 43 | "bryellow" => Self::BrYellow, 44 | "brpurple" => Self::BrPurple, 45 | "brcyan" => Self::BrCyan, 46 | "brwhite" => Self::BrWhite, 47 | "brblack" => Self::BrBlack, 48 | other if other.starts_with('#') => { 49 | let bytes = <[u8; 3]>::from_hex(&other[1..])?; 50 | let bytes_4 = [0, bytes[0], bytes[1], bytes[2]]; 51 | Color::Hex(u32::from_be_bytes(bytes_4)) 52 | } 53 | _ => return Err(crate::Error::color_format()), 54 | }; 55 | Ok(color) 56 | } 57 | } 58 | 59 | impl FromSource for Color { 60 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 61 | children!(tree, "color"); 62 | let color = tree.node().utf8_text(source)?.parse()?; 63 | tree.goto_parent(); 64 | Ok(color) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/stylesheet.rs: -------------------------------------------------------------------------------- 1 | use crate::resolver::Resolver; 2 | use std::path::Path; 3 | use std::str::FromStr; 4 | use tree_sitter::TreeCursor; 5 | 6 | use super::{Declaration, Import, Rule, helper::*}; 7 | 8 | #[derive(Clone, Debug, Default)] 9 | pub struct Stylesheet { 10 | pub(crate) imports: Vec, 11 | pub(crate) variables: Vec, 12 | pub(crate) rules: Vec, 13 | } 14 | 15 | impl Stylesheet { 16 | pub(crate) fn load(path: impl AsRef, resolver: &R) -> crate::Result { 17 | let source = resolver 18 | .read_to_string(path.as_ref()) 19 | .map_err(|e| crate::Error::missing_module(e, path.as_ref()))?; 20 | Self::from_str(&source) 21 | } 22 | } 23 | 24 | impl FromStr for Stylesheet { 25 | type Err = crate::Error; 26 | 27 | fn from_str(source: &str) -> Result { 28 | let tree = crate::parser::parse(source).unwrap(); 29 | let mut cursor = tree.walk(); 30 | Self::from_source(&mut cursor, source.as_ref()) 31 | } 32 | } 33 | 34 | impl FromSource for Stylesheet { 35 | fn from_source(tree: &mut TreeCursor, source: &[u8]) -> crate::Result { 36 | let mut stylesheet = Self::default(); 37 | if !children!(tree, "stylesheet") { 38 | return Ok(stylesheet); 39 | } 40 | while { 41 | if !tree.node().is_extra() { 42 | match tree.node().kind() { 43 | "import" => stylesheet.imports.push(Import::from_source(tree, source)?), 44 | "declaration" => stylesheet 45 | .variables 46 | .push(Declaration::from_source(tree, source)?), 47 | "rule" => stylesheet.rules.push(Rule::from_source(tree, source)?), 48 | name => return Err(crate::Error::invalid("stylesheet_item", name)), 49 | } 50 | } 51 | tree.goto_next_sibling() 52 | } {} 53 | tree.goto_parent(); 54 | Ok(stylesheet) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /syncat-stylesheet/src/ast/rule.rs: -------------------------------------------------------------------------------- 1 | use super::{Selector, Style, Value, helper::*}; 2 | use crate::{Matches, Query}; 3 | use std::collections::BTreeMap; 4 | use tree_sitter::TreeCursor; 5 | 6 | #[derive(Clone, Debug)] 7 | pub(crate) struct Rule { 8 | pub(crate) selectors: Vec, 9 | pub(crate) styles: Vec