-
-
Notifications
You must be signed in to change notification settings - Fork 141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[grammar-finder] Add new Core Package #909
base: master
Are you sure you want to change the base?
Changes from all commits
fddc8c4
818a74c
d49e0bd
687133f
f227fa6
e7f26ca
1224515
7e54ac2
d695ef7
3a6c76b
ac09e4f
e746b95
4a998f5
3b526a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Grammar-Finder | ||
|
||
Discover language grammars for unrecognized files. | ||
|
||
## AutoFind | ||
|
||
With 'AutoFind' enabled, when Pulsar fails to locate a grammar for the file you've just opened, defaulting to 'Plain Text', `grammar-finder` will automatically contact the Pulsar Package Registry in search of a community package that provides syntax highlighting for the file currently opened. | ||
|
||
If any packages are found you can easily view the whole list and install the one that looks best. | ||
|
||
When an 'AutoFind' notification appears you can quickly select: | ||
* 'View Available Packages' to view the packages found. | ||
* 'Disable Grammar-Finder for <ext>' to add this extension to the `ignoreExtList`. | ||
* 'Disable AutoFind' to disable 'AutoFind' completely. | ||
|
||
## Command Palette | ||
|
||
`grammar-finder` adds `grammar-finder:find-grammars-for-file` to the Command Palette, so that at any time you can check if any community packages provide syntax highlighting for the file you are currently working in. | ||
|
||
This makes it possible to find grammars for _recognized_ file types — or for unrecognized file types if you’ve disabled `autoFind`. | ||
|
||
## Configuration | ||
|
||
### `autoFind` | ||
|
||
When enabled, `autoFind` will show a notification inviting you to install a suitable grammar for an unrecognized file type. | ||
|
||
### `ignoreExtList` | ||
|
||
Any file extensions can be added to this list to disable all automatic checks for community packages for those file types. Choosing the “Disable `grammar-finder` for X” option on an `autoFind` notification will automatically add a given file extension to this list. This field should contain a comma-separated list of file extensions without any leading `.`s. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
const { CompositeDisposable } = require("atom"); | ||
const path = require("path"); | ||
const PackageListView = require("./package-list-view.js"); | ||
|
||
class GrammarFinder { | ||
activate() { | ||
|
||
// This local variable is intended to act as 'session' storage, or editing | ||
// session storage. Where the next time the editor is opened it's info is gone | ||
this.promptedForExt = []; | ||
|
||
atom.grammars.emitter.on("did-auto-assign-grammar", async (data) => { | ||
if (!atom.config.get("grammar-finder.autoFind")) { | ||
// autofind is turned off | ||
return; | ||
} | ||
|
||
let extOrFalse = this.inspectAssignment(data); | ||
if (!extOrFalse) { | ||
// We got false from inspectAssignment() we don't need to act | ||
return; | ||
} | ||
|
||
const ext = extOrFalse.replace(".", ""); | ||
|
||
const ignoreExtList = atom.config.get("grammar-finder.ignoreExtList"); | ||
|
||
if (ignoreExtList.includes(ext)) { | ||
// we have been told to ignore this ext | ||
return; | ||
} | ||
|
||
if (this.promptedForExt.includes(ext)) { | ||
// If we have already prompted for this extension in this editing session | ||
return; | ||
} | ||
|
||
const packages = await this.checkForGrammars(ext); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you can use |
||
|
||
if (packages.length === 0) { | ||
// No packages were found that support this grammar | ||
return; | ||
} | ||
|
||
this.promptedForExt.push(ext); | ||
|
||
// Lets notify the user about the found packages | ||
this.notify(packages, ext, "Pulsar couldn't identify an installed grammar for this file."); | ||
}); | ||
|
||
this.disposables = new CompositeDisposable(); | ||
|
||
this.disposables.add( | ||
atom.commands.add("atom-workspace", { | ||
"grammar-finder:find-grammars-for-file": async () => { | ||
// Here we can let users find a grammar for the current file, even if | ||
// it's already correctly identified | ||
const grammar = atom.workspace.getActiveTextEditor().getGrammar(); | ||
const buffer = atom.workspace.getActiveTextEditor().buffer; | ||
|
||
let extOrFalse = this.inspectAssignment( | ||
{ | ||
grammar: grammar, | ||
buffer: buffer | ||
}, | ||
{ | ||
ignoreScope: true | ||
} | ||
); | ||
|
||
if (!extOrFalse) { | ||
// We didn't find any grammar, since this is manually invoked we may want to alert | ||
atom.notifications.addInfo("Grammar-Finder was unable to identify the file.", { dismissable: true }); | ||
return; | ||
} | ||
|
||
let ext = extOrFalse.replace(".", ""); | ||
|
||
const ignoreExtList = atom.config.get("grammar-finder.ignoreExtList"); | ||
|
||
if (ignoreExtList.includes(ext)) { | ||
// we have been told to ignore this ext, since manually invoked we may want to alert | ||
atom.notifications.addInfo("This file is present on Grammar-Finder's ignore list.", { dismissable: true }); | ||
return; | ||
} | ||
|
||
const packages = await this.checkForGrammars(ext); | ||
|
||
if (packages.length === 0) { | ||
// No packages were found that support this grammar | ||
// since manuall invoked we may want to notify | ||
atom.notifications.addInfo(`Unable to locate any Grammars for '${ext}'.`, { dismissable: true }); | ||
return; | ||
} | ||
|
||
// Lets notify the user about the found packages | ||
this.notify(packages, ext, `'${packages.length}' Installable Grammars are available for '${ext}'.`); | ||
} | ||
Comment on lines
+54
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we move all of this to a method, so it's easier to read? |
||
}) | ||
); | ||
} | ||
|
||
deactivate() { | ||
this.superagent = null; | ||
} | ||
|
||
inspectAssignment(data, opts = {}) { | ||
console.log(`grammar-finder.inspectAssignment(${data.grammar.scopeName}, ${data.buffer.getPath()})`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we only log on dev mode? Seems like a "debug info" here. |
||
// data = { grammar, buffer } | ||
// Lets first make sure that the grammar returned is one where no | ||
// grammar could be found for the file. | ||
|
||
if (data.grammar.scopeName === "text.plain.null-grammar" || opts.ignoreScope) { | ||
const filePath = data.buffer.getPath(); | ||
|
||
if (typeof filePath !== "string") { | ||
return false; | ||
} | ||
|
||
const parsed = path.parse(filePath); | ||
// NodeJS thinks that if the `.` is the first character of a filename | ||
// then it doesn't count as an extension. But according to our handling | ||
// in Pulsar, the same isn't true. | ||
let ext = false; | ||
|
||
if (typeof parsed.ext === "string" && parsed.ext.length > 0) { | ||
ext = parsed.ext; | ||
} else if (typeof parsed.name === "string" && parsed.name.length > 0) { | ||
ext = parsed.name; | ||
} | ||
|
||
console.log(`File: ${filePath} - Ext: ${ext}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here about a dev/debug mode |
||
|
||
return ext; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
async checkForGrammars(ext) { | ||
this.superagent ??= require("superagent"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is superagent? |
||
|
||
const res = await fetch( | ||
`https://api.pulsar-edit.dev/api/packages?fileExtension=${ext}`, | ||
{ | ||
headers: { | ||
"User-Agent": "Pulsar.Grammar-Finder" | ||
} | ||
} | ||
); | ||
|
||
if (res.status !== 200) { | ||
// Return empty array | ||
console.error(`Grammar-Finder received status '${res.status}' from the backend: ${res.body}`); | ||
return []; | ||
} | ||
|
||
return res.json(); | ||
} | ||
|
||
notify(packages, ext, title) { | ||
atom.notifications.addInfo( | ||
title, | ||
{ | ||
description: "Would you like to see installable packages that **may** support this file type?", | ||
dismissable: true, | ||
buttons: [ | ||
{ | ||
text: "View Available Packages", | ||
onDidClick: () => { | ||
let packageListView = new PackageListView(packages); | ||
packageListView.toggle(); | ||
} | ||
}, | ||
{ | ||
text: `Don't suggest packages for '${ext}' files`, | ||
onDidClick: () => { | ||
let ignoreExtList = atom.config.get("grammar-finder.ignoreExtList"); | ||
ignoreExtList.push(ext); | ||
atom.config.set("grammar-finder.ignoreExtList", ignoreExtList); | ||
} | ||
}, | ||
{ | ||
text: "Never suggest packages for unrecognized files", | ||
onDidClick: () => { | ||
atom.config.set("grammar-finder.autoFind", false); | ||
} | ||
} | ||
] | ||
} | ||
); | ||
|
||
} | ||
} | ||
|
||
module.exports = new GrammarFinder(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This relates to my comment: #907 (comment)
Basically, we usually have an API like
onDid...
to add callbacks. I think it's a good idea to add one to the other PR, and use it here.In any way - we should never add a callback without a cleanup, so we might want to add a
CompositeDisposable
here and dispose it when deactivating package