This mapping is unfinished: 5717 of 5717 nodes are still unmarked.

Code view:

A painting is a person's account of this edit as text, recorded independently of the node mapping - a rendering often has several equally defensible answers where the mapping has one. Deletions and insertions carry no position on the opposite side in a painting, so that panel draws no caret for them.

Before

…lines 1–66 unchanged (66 lines)
67
68/// Returns the best guess language for a given file extension.
69///
70/// Note that some extensions are not uniquely identifiable so the highest probability result is
71/// returned. It may or may not be correct.
72pub fn language_for_extension(ext: &str) -> Option<Language> {
73 match ext {
74 // Sorted alphabetically.
75 "bash" | "sh" => Some(Language::ShellScript),
76 "bazel" => Some(Language::Bazel),
77 "c" | "h" => Some(Language::C),
78 "cc" | "cpp" | "cxx" | "hpp" | "hh" | "hxx" => Some(Language::CPP),
79 "cs" => Some(Language::CSharp),
80 "css" | "scss" => Some(Language::CSS),
81 "dart" => Some(Language::Dart),
82 "el" => Some(Language::Lisp),
83 "go" => Some(Language::Go),
84 "html" | "htm" => Some(Language::HTML),
85 "java" => Some(Language::Java),
86 "js" | "mjs" | "cjs" | "jsx" => Some(Language::JavaScript),
87 "json" => Some(Language::JSON),
88 "kt" => Some(Language::Kotlin),
89 "lua" => Some(Language::LUA),
90 "md" | "markdown" => Some(Language::MarkDown),
91 "php" => Some(Language::PHP),
92 "proto" => Some(Language::ProtoBuf),
93 "py" | "pyi" | "pyw" => Some(Language::Python),
94 "r" => Some(Language::R),
95 "rb" => Some(Language::Ruby),
96 "rs" => Some(Language::Rust),
97 "scala" => Some(Language::Scala),
98 "sql" => Some(Language::SQL),
99 "swift" => Some(Language::Swift),
100 "ts" | "mts" | "cts" => Some(Language::TypeScript),
101 "tsx" => Some(Language::TSX),
102 "vim" => Some(Language::Vimscript),
103 "yaml" | "yml" => Some(Language::YAML),
104 "xml" | "xht" | "xhtml" => Some(Language::XML),
105 _ => None,
106 }
107}
108
109/// Returns the treesitter language structure, if supported.
110pub fn to_treesitter(language: &Language) -> Option<tree_sitter::Language> {
111 match language {
112 // alphabetically sorted
113 Language::C => Some(tree_sitter_c::LANGUAGE.into()),
114 Language::CPP => Some(tree_sitter_cpp::LANGUAGE.into()),
115 Language::CSS => Some(tree_sitter_css::LANGUAGE.into()),
…lines 116–227 unchanged (112 lines)

After

…lines 1–65 unchanged (65 lines)
66}
67
68/// Returns the best guess language for a given file extension.
69///
70/// Note that some extensions are not uniquely identifiable so the highest probability result is
71/// returned. It may or may not be correct.
72/// Every file extension CodeDiff recognises, lower-cased, and the language it means. The one
73/// table behind [`language_for_extension`] and the README's language list.
74pub const EXTENSIONS: &[(&[&str], Language)] = &[
75 (&["bash", "sh"], Language::ShellScript),
76 (&["bazel"], Language::Bazel),
77 (&["c", "h"], Language::C),
78 (&["cc", "cpp", "cxx", "hpp", "hh", "hxx"], Language::CPP),
79 (&["cs"], Language::CSharp),
80 (&["css", "scss"], Language::CSS),
81 (&["dart"], Language::Dart),
82 (&["el"], Language::Lisp),
83 (&["go"], Language::Go),
84 (&["html", "htm"], Language::HTML),
85 (&["java"], Language::Java),
86 (&["js", "mjs", "cjs", "jsx"], Language::JavaScript),
87 (&["json"], Language::JSON),
88 (&["kt"], Language::Kotlin),
89 (&["lua"], Language::LUA),
90 (&["md", "markdown"], Language::MarkDown),
91 (&["php"], Language::PHP),
92 (&["proto"], Language::ProtoBuf),
93 (&["py", "pyi", "pyw"], Language::Python),
94 (&["r"], Language::R),
95 (&["rb"], Language::Ruby),
96 (&["rs"], Language::Rust),
97 (&["scala"], Language::Scala),
98 (&["sql"], Language::SQL),
99 (&["swift"], Language::Swift),
100 (&["ts", "mts", "cts"], Language::TypeScript),
101 (&["tsx"], Language::TSX),
102 (&["vim"], Language::Vimscript),
103 (&["yaml", "yml"], Language::YAML),
104 (&["xml", "xht", "xhtml"], Language::XML),
105];
106
107pub fn language_for_extension(ext: &str) -> Option<Language> {
108 EXTENSIONS
109 .iter()
110 .find(|(extensions, _)| extensions.contains(&ext))
111 .map(|(_, language)| *language)
112}
113
114/// The language's name as a person writes it, where the variant name is not that.
115pub fn human_name(language: Language) -> String {
116 match language {
117 Language::CPP => "C++".into(),
118 Language::CSharp => "C#".into(),
119 Language::LUA => "Lua".into(),
120 Language::MarkDown => "Markdown".into(),
121 Language::ProtoBuf => "Protocol Buffers".into(),
122 Language::ShellScript => "Shell (Bash)".into(),
123 Language::Lisp => "Emacs Lisp".into(),
124 other => other.to_string(),
125 }
126}
127
128/// The README's "Supported languages" section, generated so it cannot drift from this file: one
129/// table of the languages with a grammar, and the extensions that are recognised but diffed as
130/// plain text because no grammar is compiled in.
131pub fn supported_languages_markdown() -> String {
132 use strum::IntoEnumIterator;
133
134 let extensions_of = |language: Language| -> String {
135 EXTENSIONS
136 .iter()
137 .filter(|(_, candidate)| *candidate == language)
138 .flat_map(|(extensions, _)| extensions.iter())
139 .map(|extension| format!("`.{extension}`"))
140 .collect::<Vec<_>>()
141 .join(", ")
142 };
143 let mut with_grammar: Vec<Language> = Vec::new();
144 let mut plain_text: Vec<Language> = Vec::new();
145 for language in Language::iter().filter(|language| *language != Language::Unknown) {
146 if to_treesitter(&language).is_some() {
147 with_grammar.push(language);
148 } else {
149 plain_text.push(language);
150 }
151 }
152 with_grammar.sort_by_key(|language| human_name(*language).to_lowercase());
153 plain_text.sort_by_key(|language| human_name(*language).to_lowercase());
154
155 let mut out = String::new();
156 out.push_str(&format!(
157 "{} languages are parsed with a tree-sitter grammar and diffed structurally:\n\n",
158 with_grammar.len()
159 ));
160 out.push_str("| Language | File extensions |\n|---|---|\n");
161 for language in &with_grammar {
162 out.push_str(&format!(
163 "| {} | {} |\n",
164 human_name(*language),
165 extensions_of(*language)
166 ));
167 }
168 out.push_str(
169 "\nRecognised by extension but diffed as plain text, since no grammar is compiled in: ",
170 );
171 out.push_str(
172 &plain_text
173 .iter()
174 .map(|language| format!("{} ({})", human_name(*language), extensions_of(*language)))
175 .collect::<Vec<_>>()
176 .join(", "),
177 );
178 out.push_str(".\n");
179 out
180}
181
182pub fn to_treesitter(language: &Language) -> Option<tree_sitter::Language> {
183 match language {
184 // alphabetically sorted
185 Language::C => Some(tree_sitter_c::LANGUAGE.into()),
186 Language::CPP => Some(tree_sitter_cpp::LANGUAGE.into()),
…lines 187–339 unchanged (153 lines)

Before

source_file
block_comment
/* "/*"
*/ "*/"
use_declaration
use "use"
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "code"
:: "::"
identifier "Language"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Returns the language for a given path.\n"
function_item (+120 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Refines [`language_for_path`]'s extension-derived guess by "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " collision where a content check is cheap, unambiguous, and "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " overwhelming majority of cases, but Qt Linguist also uses `"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " files (`<?xml version=\"1.0\"?><!DOCTYPE TS>...`) - a real, r"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " project), not a one-off. Unlike a fuzzy content heuristic, "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " unconditionally: a file starting with an XML declaration ca"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " there is no genuine TypeScript source this could misclassif"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Every other extension collision this project has hit in pra"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " project's C runtime files instead of R) has been a one-off,"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " than a recurring pattern, so it's handled by rejecting that"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " general content heuristic here - see `sample.csv`'s REJECTE"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " discussion this function came out of.\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Callers that already have the file's content in hand (e.g. "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " which reads the whole file before determining its language "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " [`language_for_path`] - it can only ever be as good or bett"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " beyond a `starts_with` check. Callers that only have a path"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " add real I/O cost against a large corpus (e.g. `sample_test"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " checks extension before ever touching a blob), should keep "...
function_item (+90 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " True if `content` opens with an XML declaration, ignoring a"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Not narrowed to Qt Linguist's `<!DOCTYPE TS>`: any XML name"...
function_item (+44 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Returns the best guess language for a given file extension."...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Note that some extensions are not uniquely identifiable so "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " returned. It may or may not be correct.\n"
function_item (+669 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Returns the treesitter language structure, if supported.\n"
function_item (+617 nodes collapsed)
attribute_item
# "#"
[ "["
attribute
identifier "cfg"
token_tree
( "("
identifier "test"
) ")"
] "]"
mod_item (+574 nodes collapsed)

After

source_file
block_comment
/* "/*"
*/ "*/"
use_declaration
use "use"
scoped_identifier
scoped_identifier
crate "crate"
:: "::"
identifier "code"
:: "::"
identifier "Language"
; ";"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Returns the language for a given path.\n"
function_item (+120 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Refines [`language_for_path`]'s extension-derived guess by "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " collision where a content check is cheap, unambiguous, and "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " overwhelming majority of cases, but Qt Linguist also uses `"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " files (`<?xml version=\"1.0\"?><!DOCTYPE TS>...`) - a real, r"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " project), not a one-off. Unlike a fuzzy content heuristic, "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " unconditionally: a file starting with an XML declaration ca"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " there is no genuine TypeScript source this could misclassif"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Every other extension collision this project has hit in pra"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " project's C runtime files instead of R) has been a one-off,"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " than a recurring pattern, so it's handled by rejecting that"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " general content heuristic here - see `sample.csv`'s REJECTE"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " discussion this function came out of.\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Callers that already have the file's content in hand (e.g. "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " which reads the whole file before determining its language "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " [`language_for_path`] - it can only ever be as good or bett"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " beyond a `starts_with` check. Callers that only have a path"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " add real I/O cost against a large corpus (e.g. `sample_test"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " checks extension before ever touching a blob), should keep "...
function_item (+90 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " True if `content` opens with an XML declaration, ignoring a"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Not narrowed to Qt Linguist's `<!DOCTYPE TS>`: any XML name"...
function_item (+44 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Returns the best guess language for a given file extension."...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment "\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Note that some extensions are not uniquely identifiable so "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " returned. It may or may not be correct.\n"
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " Every file extension CodeDiff recognises, lower-cased, and "...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " table behind [`language_for_extension`] and the README's la"...
const_item (+671 nodes collapsed)
function_item (+80 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " The language's name as a person writes it, where the varian"...
function_item (+170 nodes collapsed)
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " The README's \"Supported languages\" section, generated so it"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " table of the languages with a grammar, and the extensions t"...
line_comment
// "//"
outer_doc_comment_marker
/ "/"
doc_comment " plain text because no grammar is compiled in.\n"
function_item (+560 nodes collapsed)
function_item (+617 nodes collapsed)
attribute_item
# "#"
[ "["
attribute
identifier "cfg"
token_tree
( "("
identifier "test"
) ")"
] "]"
mod_item (+898 nodes collapsed)