jupyterlab / jupyterlab

JupyterLab computational environment.
https://jupyterlab.readthedocs.io/
Other
14.24k stars 3.42k forks source link

Associate file type to an existing text editor syntax highlight or a custom one. #7427

Open willibix opened 5 years ago

willibix commented 5 years ago

There already issue #4223 (and all those related one: #5064, #4005, #3858, #4048, #6442, #6813) that is talking about this, but none of them seem to be giving a working solution. I have already try what @BoPeng suggest in issue #4423 but it's not working and I kind of have to figure a solution quickly for this. So that's why I'm re-posting this issue, to have some feedback and have a clear solution, because all those issue are kind of dated and it's not clear what is available in the curent 1.1 version.

I have a file format that I want to open with the text editor (codemirror) and the syntax highlighter mathematica that is already there. So I did an application plugins and used the @jupyterlab/application.JupyterFrontEnd.docRegistry.addFileType(), but it's not working like I want it to. It's opening the text editor but it's not setting the language (syntaxe highlighter) correctly. I tough that the "mimeTypes" was the thing that specified to the text editor what syntax highlight to use, but apparently it's not the case. I tried many type of mimeTypes but it's not changing the result.

Here's my code:

import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application';
import "../style/index.css";

// const MIME_TYPE = 'application/vdn.reactivecore.trd';
// const TRD_MIME_TYPE = 'application/vnd.wolfram.mathematica';
const TRD_MIME_TYPE = 'application/json';
// const OWL_MIME_TYPE = 'text/xml';

/**
 * Add the ReactiveCore file type into Jupyterlab document registery.
 */
const registerReactiveCoreFileType = (app: JupyterFrontEnd) => {
    app.docRegistry.addFileType({
        name: "TRD",
        displayName: "TRD File",
        extensions: [".trd", ".rrx", ".rrl", ".rrd", ".rr"],
        mimeTypes: [TRD_MIME_TYPE],
        iconClass: "jp-MaterialIcon reactivecore_icon"
    });
}

/**
 * Initialization data for the jupyterlab-ext-reactivecore-filetype extension.
 */
const extension: JupyterFrontEndPlugin<void> = {
    id: 'jupyterlab-ext-reactivecore-filetype',
    autoStart: true,
    activate: (app: JupyterFrontEnd) => {
        console.log('JupyterLab extension jupyterlab-ext-reactivecore-filetype is activated!');
        registerReactiveCoreFileType(app)
    }
};

export default extension;

I also tried to do a Mime Renderer Extensions, but it's seem to only give you the possibility to do your own render, where I would simply like to use the already existing jupyterlab code editor (codemirror) with a specific syntax highlight.

So what can I did to have the behaviour I'm locking for?

Also, when I have this working, I would like to tried to add a codemirror mode to have my own syntaxe highlighter, but again I see a lot of issue open on that mater, like #5504 and #5829 but no good documentation on the subject, so some help would also be appreciated for this to.

willibix commented 5 years ago

I finally found a solution. The key is this little line: Mode.getModeInfo().push(). I found the answer by exploring the source code and with the help of #7143, so thanks @wolfv. I will also post the answer in #4223 for reference.

First, here's the complete code I used to associate file type to a specific text editor syntax highlight:

import { JupyterFrontEnd, JupyterFrontEndPlugin } from "@jupyterlab/application";
import { Mode } from "@jupyterlab/codemirror";
import "../style/index.css";

const RR_MIME_TYPE = "text/x-mathematica";
const OWL_MIME_TYPE = "text/xml";

/**
 * Add the ReactiveCore file type into JupyterLab document registry and the CodeMirror mode.
 */
const registerReactiveCoreFileType = (app: JupyterFrontEnd) => {
    Mode.getModeInfo().push({
        name: ".ReactiveCore RR",
        mime: RR_MIME_TYPE,
        mode: "mathematica",
        ext: ["trd", "rrx", "rrl", "rrd", "rr"]
    });

    Mode.getModeInfo().push({
        name: ".ReactiveCore OWL",
        mime: OWL_MIME_TYPE,
        mode: "xml",
        ext: ["owl"]
    });

    app.docRegistry.addFileType({
        name: "rr",
        displayName: "RR File",
        extensions: [".trd", ".rrx", ".rrl", ".rrd", ".rr"],
        mimeTypes: [RR_MIME_TYPE],
        iconClass: "jp-MaterialIcon reactivecore_icon",
        iconLabel: "",
        contentType: "file",
        fileFormat: "text"
    });

    app.docRegistry.addFileType({
        name: "owl",
        displayName: "OWL File",
        extensions: [".owl"],
        mimeTypes: [OWL_MIME_TYPE],
        iconClass: "jp-MaterialIcon reactivecore_icon",
        iconLabel: "",
        contentType: "file",
        fileFormat: "text"
    });

    /**
     * Code to see all CodeMirror mode available in JupyterLab and the whole application object for debug
     */
    // let test = Mode.getModeInfo();
    // console.log(test)
    // console.log(app)
}

/**
 * Initialization data for the jupyterlab-ext-reactivecore-filetype extension.
 */
const extension: JupyterFrontEndPlugin<void> = {
    id: "jupyterlab-ext-reactivecore-filetype",
    autoStart: true,
    activate: (app: JupyterFrontEnd) => {
        console.log("JupyterLab extension jupyterlab-ext-reactivecore-filetype is activated!");
        registerReactiveCoreFileType(app)
    }
};

export default extension;

You will need those 3 dependencies in your "package.json" for this code to work: "@jupyterlab/application", "@jupyterlab/codemirror", "@types/codemirror"

About this code: 1) The only concrete thing that docRegistry.addFileType() function does is to associate the file type with the image icon. Strangely enough, the mime type in the docRegistry.addFileType() and getModeInfo().push() don’t have to match for it to work. But "mime" and "mode" properties in getModeInfo().push() have to match the syntax highlight (CodeMirror mode) you want to use. To have a complete list of those available in JupyterLab and their properties, print the result of Mode.getModeInfo(). 2) It's the "ext" property in getModeInfo().push() that associate your file type to the syntax highlight you want. 3) When you open your file, the "name" property in getModeInfo().push() will be displayed in the bottom left corner of the application (current syntax highlight of the editor) . But the first name in the CodeMirror mode list (alphabetically ordered) that match the mode/mime of the file, will be the one displayed. For example: in my RR file type, if I put "ReactiveCore RR" in the "name" property, it will display "Mathematica" as the current editor's syntax highlight. But since I put a dot in front of my"name" property, it showed my value instead (eg. ".ReactiveCore RR"). I don't think it's the intended behavior, but it's just how it works in the current version.

I hope this will be help some people with this problem 🙂

jasongrout commented 5 years ago

Thank you very much! I think this would be a great "recipe" addition to the docs.

jasongrout commented 5 years ago

Would you mind contributing to the docs? Or if you don't have time, would you mind if someone else packaged up your comments above as a new doc on how to do this?

willibix commented 5 years ago

I'm not realy good with documentation and stuff and I don't realy have the time right now to do it.

But I don't mind at all if some one else packaged up my comments as a new doc. In fact it would be my pleasure.

Just to help a little bit with that, I edited my comment with some spelling correction and rewording (I want to thanks my wife for that :P).

Thanks @jasongrout for the great feedback, it's realy appreciated.

jasongrout commented 5 years ago

Reopening as a good first doc issue, then. Thanks!

TermeHansen commented 4 years ago

as stated, I have also noticed that: "The only concrete thing that docRegistry.addFileType() function does is to associate the file type with the image icon", So how de we make a new filetype associate the right mimeType to it?