[PYTHON] Add D (any other language) to SublimeLinter for highlighting

Sublime Linter is one of the packages of Sublime Text2, and it is a function to highlight the part where the compilation error or syntax error occurred. It looks like the image below.

SublimeLinter例

The official page for Sublime Linter is below. https://github.com/SublimeLinter/SublimeLinter

See the following page for installation of Sublime Linter. http://perl.no-tubo.net/2012/05/03/mac%E3%81%AE%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF-sublime-text2%E3%81%A7javascript%E3%81%AE%E3%82%B7%E3%83%B3%E3%82%BF%E3%83%83%E3%82%AF%E3%82%B9%E3%82%A8%E3%83%A9/ http://watson1978.github.com/blog/2012/08/23/make-a-sublime-text-environment/

So, here's how to highlight the D language with this.

Add file for D language

After installing SublimeLinter, open the folder containing the packages with [Sublime Text 2]-> [Preference]-> [Browse Packages…]. (For MacOS. I don't know other OS) BrowsePackage…

Then, when you open the folder containing the package, open the [~~ / Packages / SublimeLinter / sublimelinter / modules /] folder. I think that python.py or java.py is included in it, so create d.py.

Create d.py river

Copy the source from objective-j.py to d.py, delete unnecessary parts and do as follows.

d.py


import re
import os
import subprocess

from base_linter import BaseLinter

CONFIG = {
    'language': 'D'
}


class Linter(BaseLinter):
    def built_in_check(self, view, code, filename):
        return ''

    def parse_errors(self, view, errors, lines, errorUnderlines, violationUnderlines, warningUnderlines, errorMessages, violationMessages, warningMessages):
		return ''

built_in_check is the function that compiles the code and returns a compilation error, and parse_errors is the function that decides where to highlight based on the error that came from built_in_check.

Contents of built_in_check

The arguments for built_in_check are self, view, code, filename. self is confident (this in C #), view is a tab class, code is ** the contents of an unsaved file being edited **, and filename is the name of the file being displayed. So, I write the contents processing to compile the code in'built_in_check', but the notes are as follows.

  1. The compilation target is code. Compiling the filename file will compile the unedited file, which is strange. Save the code in a suitable folder with d.py and compile it
  2. The dmd compile option is -c -o- -w -unittest -debug
  3. If you don't understand, read base_linter.py

So the result is below.

d.py


…
#Temp folder to write the file in the middle of writing
TMPPATH_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '.dtmpfiles'))
if not os.path.exists(TMPPATH_DIR):
    os.mkdir(TMPPATH_DIR)
…
class Linter(BaseLinter):
    def built_in_check(self, view, code, filename):
      def built_in_check(self, view, code, filename):
        #Get pass
        work_path = os.path.dirname(filename)
        file_name = os.path.basename(filename)

		 #Get compile location settings
        settings = view.settings().get('SublimeLinter', {}).get(self.language, {})
        if(settings):
            dwd = settings.get('working_directory', [])
            if(dwd):
                #Get it if set in the project
                work_path = dwd

        #The file in the middle of writing is used as a temp file..Export directly under py
        tempfilePath = os.path.join(TMPPATH_DIR, file_name)

        with open(tempfilePath, 'w') as f:
            f.write(code)

        args = ["dmd", "-c", "-o-", "-w", "-unittest", "-debug", tempfilePath]

        try:
			#compile
            process = subprocess.Popen(args,
                                        cwd=work_path,
                                        stdin=subprocess.PIPE,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.STDOUT,
                                        startupinfo=self.get_startupinfo())
            result = process.communicate(None)[0]
        finally:
            if tempfilePath:
                #Delete saved file
                os.remove(tempfilePath)

        return result.strip()
…

SublimeText2 has a project management function, but if you write the settings in the project file, you can set the location to dmd. If you do not import the module you made yourself, a compile error will occur in the import part (I think). The settings are as follows.

xxx.sublime-project


{
	"folders":
	[
		{
			//Project folder
			"path": "~~~~"
		}
	],

	"settings":
    {
        "SublimeLinter":
        {
            "d":
            {
				//dmd The folder you want to move. It may be the same as the folder above.
                "working_directory": "~~~~~"
            }
        }
    }
}

Contents of parse_errors

The error message of the compilation error passed in the return of built_in_check is passed to lines of the parse_errors argument. After that, cut out the error message and the error line from the error message in each line of lines and pass it to the self.add_message function. The points to note here are as follows.

  1. In v2.060 of dmd, a compilation error is spit out in a place other than the source I wrote. This will be fixed. At this stage, I put all the errors in the line I'm importing on the premise that I'm importing if it's spit out.
  2. ʻerror Messages` is passed, but it doesn't make much sense here. I mean, I haven't checked what will come. Maybe nothing is in it.
  3. If you don't understand, read base_linter.py (it's important, so the second time)

So (ry

d.py


…
    def parse_errors(self, view, errors, lines, errorUnderlines, violationUnderlines, warningUnderlines, errorMessages, violationMessages, warningMessages):
        for line in errors.splitlines():
            match = re.match(r'^(?P<filename>.+\.d)\((?P<line>\d+)\): Error: (?P<error>.+)', line)

            if match:
                tab_filename = os.path.basename(view.file_name())
                error_filename = os.path.basename(match.group('filename'))
                error, line = match.group('error'), match.group('line')
                if(tab_filename == error_filename):
                    self.add_message(int(line), lines, error, errorMessages)
                else:
                    line = 1
                    module_name = error_filename.replace('.d', '')
                    regions = view.find_all(r'import.*\.' + module_name)
                    if(regions):
                        line = view.rowcol(regions[0].a)[0] + 1
                    self.add_message(line, lines, error, errorMessages)

This should probably work. If it doesn't work, please fix it.

Recommended Posts

Add D (any other language) to SublimeLinter for highlighting
Add syntax highlighting for the Kv language to Spyder in the Python IDE
(For myself) Flask_5 (Add to txt file)
[ESXi (vCenter)] How to add NIC for CentOS 7.3