다중 언어 하이라이트

발행: (2025년 12월 2일 오전 11:13 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

이 포스트에서 설명하는 변경 사항은 multilingual 브랜치에 있는 Kilo-go GitHub 저장소에서 확인할 수 있습니다.

리팩터링: syntax 구조체를 별도 패키지로 이동

EditorSyntax 구조체를 별도 패키지로 추출하여 에디터가 해당 패키지에 정의된 메서드를 사용할 수 있게 했습니다.

syntax/syntax.go

package syntax

import "github.com/alcb1310/kilo-go/utils"

var GO_HL_EXTENSIONS = []string{".go"}
var GO_HL_KEYWORDS = []string{
	"package", "import", "func", "type", "var", "const", "if", "else",
	"switch", "case", "default", "for", "range", "goto", "continue",
	"select", "return", "break",
}
var GO_HL_TYPES = []string{
	"bool", "byte", "error", "float32", "float64", "int", "int16", "int32",
	"int64", "int8", "rune", "string", "uint", "uint16", "uint32", "uint64", "uint8",
}

var GO_SYNTAX = EditorSyntax{
	Filetype:              "go",
	Filematch:             GO_HL_EXTENSIONS,
	Flags:                 utils.HL_HIGHLIGHT_NUMBER | utils.HL_HIGHLIGHT_STRING,
	SingleLineComment:     "//",
	MultiLineCommentStart: "/*",
	MultiLineCommentEnd:   "*/",
	Keywords:              GO_HL_KEYWORDS,
	Types:                 GO_HL_TYPES,
}

type EditorSyntax struct {
	Filetype              string
	Filematch             []string
	Flags                 uint
	SingleLineComment     string
	MultiLineCommentStart string
	MultiLineCommentEnd   string
	Keywords              []string
	Types                 []string
}

// HLDB holds all supported syntaxes.
var HLDB = []EditorSyntax{
	GO_SYNTAX,
	// C_SYNTAX will be added later.
}

에디터 내 업데이트된 참조

editor/editor.go

type EditorConfig struct {
	// …
	syntax *syntax.EditorSyntax
}

editor/output.go

func (e *EditorConfig) editorDrawStatusBar(abuf *ab.AppendBuffer) {
	// …
	if e.syntax != nil {
		filetype = "[" + e.syntax.Filetype + "]"
	}
	// …
}

editor/syntax.go

func (e *EditorConfig) editorUpdateSyntax(row *EditorRow) {
	// …
	scs := e.syntax.SingleLineComment
	mcs := e.syntax.MultiLineCommentStart
	mce := e.syntax.MultiLineCommentEnd
	keywords := e.syntax.Keywords
	types := e.syntax.Types
	// …
	if e.syntax.Flags&utils.HL_HIGHLIGHT_STRING == 2 {
		// handle strings
	}
	if e.syntax.Flags&utils.HL_HIGHLIGHT_NUMBER == 1 {
		// handle numbers
	}
	// …
}

C/C++ 지원 추가

새로운 EditorSyntax 값을 정의하여 C/C++ 지원을 추가합니다.

syntax/go.go (변경 없음)

package syntax

import "github.com/alcb1310/kilo-go/utils"

var GO_HL_EXTENSIONS = []string{".go"}
var GO_HL_KEYWORDS = []string{
	"package", "import", "func", "type", "var", "const", "if", "else",
	"switch", "case", "default", "for", "range", "goto", "continue",
	"select", "return", "break",
}
var GO_HL_TYPES = []string{
	"bool", "byte", "error", "float32", "float64", "int", "int16", "int32",
	"int64", "int8", "rune", "string", "uint", "uint16", "uint32", "uint64", "uint8",
}

var GO_SYNTAX = EditorSyntax{
	Filetype:              "go",
	Filematch:             GO_HL_EXTENSIONS,
	Flags:                 utils.HL_HIGHLIGHT_NUMBER | utils.HL_HIGHLIGHT_STRING,
	SingleLineComment:     "//",
	MultiLineCommentStart: "/*",
	MultiLineCommentEnd:   "*/",
	Keywords:              GO_HL_KEYWORDS,
	Types:                 GO_HL_TYPES,
}

syntax/c.go

package syntax

import "github.com/alcb1310/kilo-go/utils"

var C_HL_EXTENSIONS = []string{".c", ".h", ".cpp"}

var C_SYNTAX = EditorSyntax{
	Filetype:              "c",
	Filematch:             C_HL_EXTENSIONS,
	Flags:                 utils.HL_HIGHLIGHT_NUMBER | utils.HL_HIGHLIGHT_STRING,
	SingleLineComment:     "//",
	MultiLineCommentStart: "/*",
	MultiLineCommentEnd:   "*/",
	Keywords: []string{
		"switch", "if", "while", "for", "break", "continue", "return", "else",
		"struct", "union", "typedef", "static", "enum", "class", "case",
		"#include", "#define", "#ifndef", "#ifdef", "#endif", "#else",
	},
	Types: []string{
		"int", "long", "double", "float", "char", "unsigned", "signed", "void",
	},
}

HLDB에 C 구문 추가

var HLDB = []EditorSyntax{
	GO_SYNTAX,
	C_SYNTAX,
}

구문 선택 버그 수정

구문 선택 루틴이 이제 각 언어에 대해 모든 파일 매치 패턴을 순회하도록 수정되었습니다.

func (e *EditorConfig) editorSelectSyntaxHighlight() {
	// …
	for _, s := range syntax.HLDB {
		for j := range s.Filematch {
			isExt := s.Filematch[j][0] == '.'
			if (isExt && ext == s.Filematch[j]) ||
				(!isExt && strings.Contains(ext, s.Filematch[j])) {
				e.syntax = &s

				for _, row := range e.rows {
					e.editorUpdateSyntax(&row)
				}
				return
			}
		}
	}
}

에디터를 변경하지 않고 다국어 지원

각 언어에 대해 바이너리를 다시 컴파일할 필요 없이, 구문 정의를 사용자의 설정 디렉터리(${XDG_CONFIG}/kilo/highlight/)에 TOML 파일로 배치하면 됩니다. 에디터는 시작 시 이를 로드합니다.

${XDG_CONFIG}/kilo/highlight/go.toml

number = true
string = true
filetype = "GO"
extensions = [".go"]
keywords = [
    "package", "import", "func", "type", "var", "const", "if", "else",
    "switch", "case", "default", "for", "range", "goto", "continue",
    "select", "return", "break",
]
types = [
    "bool", "byte", "error", "float32", "float64", "int", "int16", "int32",
    "nil", "int64", "int8", "rune", "string", "uint", "uint16", "uint32",
    "uint64", "uint8",
]
slc = "//"
mlcs = "/*"
mlce = "*/"

${XDG_CONFIG}/kilo/highlight/c.toml

number = true
string = true
filetype = "C/CPP"
extensions = [".c", ".h", ".cpp"]
keywords = [
    "switch", "if", "while", "for", "break", "continue", "return", "else",
    "struct", "union", "typedef", "static", "enum", "class", "case",
    "#include", "#define", "#ifndef", "#ifdef", "#endif", "#else"
]
types = ["int", "long", "double", "float", "char", "unsigned", "signed", "void", "NULL"]
slc = "//"
mlcs = "/*"
mlce = "*/"

구문 정의 로드

func init() {
	// …
	syntax.LoadSyntax() // reads all *.toml files from ${XDG_CONFIG}/kilo/highlight/
}

이 방식을 사용하면 새로운 언어를 추가할 때 highlight 디렉터리에 올바르게 포맷된 TOML 파일을 넣기만 하면 되며, 에디터 소스 코드를 수정할 필요가 없습니다.

Back to Blog

관련 글

더 보기 »

Go의 비밀스러운 삶: 인터페이스

암묵적 계약의 힘. 화요일 아침에 안개가 끼었다. 이든은 커피와 작은 비스코티 상자를 들고 아카이브로 내려갔다. 엘리너가 고개를 들었다. “...

GVM (Go Version Manager) 사용 방법

GVM 설치 시스템에 GVM을 설치하려면 다음 단계를 따르세요. 1. 필요한 종속성을 설치합니다. bash sudo apt-get install curl git mercurial make binutils b...