Skip to content

Commit

Permalink
Merge pull request #941 from savetheclocktower/tree-sitter-march
Browse files Browse the repository at this point in the history
Tree-sitter rolling fixes: 1.115 edition
  • Loading branch information
savetheclocktower authored Mar 20, 2024
2 parents bc6888c + 6fe8e53 commit 1481d39
Show file tree
Hide file tree
Showing 27 changed files with 724 additions and 232 deletions.
155 changes: 105 additions & 50 deletions packages/grammar-selector/lib/grammar-list-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ module.exports = class GrammarListView {
constructor() {
this.autoDetect = { name: 'Auto Detect' };

this.configSubscription = atom.config.observe(
'grammar-selector.hideDuplicateTextMateGrammars',
(value) => {
this.hideDuplicateGrammars = value
}
);

this.selectListView = new SelectListView({
itemsClassList: ['mark-active'],
items: [],
Expand All @@ -14,36 +21,33 @@ module.exports = class GrammarListView {
if (grammar === this.currentGrammar) {
element.classList.add('active');
}
element.classList.add('grammar-item');
element.textContent = grammarName;
element.dataset.grammar = grammarName;

const div = document.createElement('div');
div.classList.add('pull-right');

if (isTreeSitter(grammar)) {
if (!this.hideDuplicateGrammars) {
// When we show all grammars, we should add a badge to each grammar
// to distinguish them from one another in the list.
const parser = document.createElement('span');

let badgeColor = 'badge-success';
let badgeText = 'Tree-sitter';

if (isLegacyTreeSitterMode()) {
// Color the legacy badge green to represent the user's preference.
badgeColor = isLegacyTreeSitter(grammar) ?
'badge-success' : 'badge-warning';
badgeText = isLegacyTreeSitter(grammar) ?
'Legacy Tree-sitter' : 'Modern Tree-sitter';
}
let badgeText = getBadgeTextForGrammar(grammar);
let badgeColor = getBadgeColorForGrammar(grammar);

parser.classList.add(
'grammar-selector-parser',
'badge',
badgeColor
);
parser.textContent = badgeText;
parser.setAttribute(
'title',
'(Recommended) A faster parser with improved syntax highlighting & code navigation support.'
);
if (isModernTreeSitter(grammar)) {
parser.setAttribute(
'title',
'(Recommended) A faster parser with improved syntax highlighting & code navigation support.'
);
}
div.appendChild(parser);
}

Expand Down Expand Up @@ -99,6 +103,16 @@ module.exports = class GrammarListView {
this.selectListView.reset();
}

getAllDisplayableGrammars() {
let allGrammars = atom.grammars
.getGrammars({ includeTreeSitter: true })
.filter(grammar => {
return grammar !== atom.grammars.nullGrammar && grammar.name;
});

return allGrammars;
}

async toggle() {
if (this.panel != null) {
this.cancel();
Expand All @@ -113,31 +127,7 @@ module.exports = class GrammarListView {
this.currentGrammar = this.autoDetect;
}

let grammars = atom.grammars
.getGrammars({ includeTreeSitter: true })
.filter(grammar => {
return grammar !== atom.grammars.nullGrammar && grammar.name;
});

// Don't show legacy Tree-sitter grammars in the selector unless the user
// has opted into it.
if (!isLegacyTreeSitterMode()) {
grammars = grammars.filter(grammar => !isLegacyTreeSitter(grammar));
}

if (atom.config.get('grammar-selector.hideDuplicateTextMateGrammars')) {
// Filter out all TextMate grammars for which there is a Tree-sitter
// grammar with the exact same name.
const blacklist = new Set();
grammars.forEach(grammar => {
if (isTreeSitter(grammar)) {
blacklist.add(grammar.name);
}
});
grammars = grammars.filter(
grammar => isTreeSitter(grammar) || !blacklist.has(grammar.name)
);
}
let grammars = this.getAllDisplayableGrammars();

grammars.sort((a, b) => {
if (a.scopeName === 'text.plain') {
Expand All @@ -149,26 +139,35 @@ module.exports = class GrammarListView {
}
return a.name.localeCompare(b.name);
});

if (this.hideDuplicateGrammars) {
let displayedGrammars = [];
let seenIds = new Set();

for (let grammar of grammars) {
if (seenIds.has(grammar.scopeName)) continue;
seenIds.add(grammar.scopeName);
displayedGrammars.push(grammar);
}

grammars = displayedGrammars;
}

grammars.unshift(this.autoDetect);
await this.selectListView.update({ items: grammars });
this.attach();
}
}
};

// We look up global settings here, but it's just to determine the badge
// colors. Otherwise we should be looking up these values in a scope-specific
// manner.
function getLanguageModeConfig() {
let isTreeSitterMode = atom.config.get('core.useTreeSitterParsers');
let isLegacy = atom.config.get('core.useLegacyTreeSitter');
if (!isTreeSitterMode) return 'textmate';
return isLegacy ? 'node-tree-sitter' : 'wasm-tree-sitter';
}

function isLegacyTreeSitterMode() {
return getLanguageModeConfig() === 'node-tree-sitter';
}

function isTreeSitter(grammar) {
return isLegacyTreeSitter(grammar) || isModernTreeSitter(grammar);
return isLegacy ? 'node-tree-sitter' : 'web-tree-sitter';
}

function isModernTreeSitter(grammar) {
Expand All @@ -183,8 +182,64 @@ function compareGrammarType(a, b) {
return getGrammarScore(a) - getGrammarScore(b);
}

// Given a scope name, determines the user's preferred parser type for that
// language.
function getParserPreferenceForScopeName(scopeName) {
let useTreeSitterParsers = atom.config.get(
'core.useTreeSitterParsers',
{ scope: [scopeName] }
);
let useLegacyTreeSitter = atom.config.get(
'core.useLegacyTreeSitter',
{ scope: [scopeName] }
);

if (!useTreeSitterParsers) {
return 'textmate';
} else if (useLegacyTreeSitter) {
return 'node-tree-sitter';
} else {
return 'web-tree-sitter';
}
}

function getBadgeTextForGrammar(grammar) {
switch (grammar.constructor.name) {
case 'Grammar':
return 'TextMate';
case 'WASMTreeSitterGrammar':
return 'Modern Tree-sitter';
case 'TreeSitterGrammar':
return 'Legacy Tree-sitter';
}
}

const BADGE_COLORS_BY_LANGUAGE_MODE_CONFIG = {
'textmate': {
'Grammar': 'badge-success',
'TreeSitterGrammar': 'badge-info',
'WASMTreeSitterGrammar': 'badge-info'
},
'web-tree-sitter': {
'WASMTreeSitterGrammar': 'badge-success',
'TreeSitterGrammar': 'badge-warning',
'Grammar': 'badge-info'
},
'node-tree-sitter': {
'TreeSitterGrammar': 'badge-success',
'WASMTreeSitterGrammar': 'badge-warning',
'Grammar': 'badge-info'
}
};

function getBadgeColorForGrammar(grammar) {
let languageModeConfig = getLanguageModeConfig();
let classNameMap = BADGE_COLORS_BY_LANGUAGE_MODE_CONFIG[languageModeConfig];
return classNameMap[grammar.constructor.name];
}

function getGrammarScore(grammar) {
let languageParser = getLanguageModeConfig();
let languageParser = getParserPreferenceForScopeName(grammar.scopeName);
if (isModernTreeSitter(grammar)) {
return languageParser === 'node-tree-sitter' ? -1 : -2;
}
Expand Down
5 changes: 3 additions & 2 deletions packages/grammar-selector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@
"showOnRightSideOfStatusBar": {
"type": "boolean",
"default": true,
"description": "Show the active pane item's language on the right side of Pulsar's status bar, instead of the left."
"description": "Show the active pane items language on the right side of Pulsars status bar, instead of the left."
},
"hideDuplicateTextMateGrammars": {
"type": "boolean",
"default": true,
"description": "Hides the TextMate grammar when there is an existing Tree-sitter grammar"
"title": "Hide Duplicate Grammars",
"description": "Hides non-preferred grammars when there is more than one grammar. When checked, whichever grammar is preferred for a given scope name (TextMate or Tree-sitter) will be the only one shown. When unchecked, all grammars will always be shown in the list, regardless of the user’s settings."
}
}
}
Loading

0 comments on commit 1481d39

Please sign in to comment.