Created
January 17, 2018 07:56
-
-
Save teryror/f07fb553a0a935e6c5a9cbd1a0add54c to your computer and use it in GitHub Desktop.
4coder Customization: Support for Golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ... | |
static int32_t* | |
get_indentation_marks(Application_Links *app, Partition *part, Buffer_Summary *buffer, Cpp_Token_Array tokens, int32_t line_start, int32_t line_end, bool32 exact_align, int32_t tab_width){ | |
int32_t indent_mark_count = line_end - line_start; | |
int32_t *indent_marks = push_array(part, int32_t, indent_mark_count); | |
// Shift the array so line_index works correctly. | |
indent_marks -= line_start; | |
// NOTE: TLD modifications begin here | |
bool tld_golang_indentation = false; | |
Parse_Context_ID parse_context_id = 0; | |
buffer_get_setting(app, buffer, BufferSetting_ParserContext, (int32_t *) &parse_context_id); | |
if (parse_context_id == tld_parse_context_language_golang) { | |
tld_golang_indentation = true; | |
} | |
// NOTE: TLD modifications end here | |
// Decide where to start indentation parsing. | |
Indent_Parse_State indent = {0}; | |
Cpp_Token *token_ptr = find_anchor_token(app, buffer, tokens, line_start, tab_width, &indent.current_indent); | |
if (token_ptr == 0){ | |
for (int32_t line_index = line_start; line_index < line_end; ++line_index){ | |
indent_marks[line_index] = 0; | |
} | |
} | |
else{ | |
int32_t line_number = buffer_get_line_number(app, buffer, token_ptr->start); | |
if (line_number > line_start){ | |
line_number = line_start; | |
} | |
if (token_ptr == tokens.tokens){ | |
indent.current_indent = 0; | |
} | |
int32_t next_line_start_pos = buffer_get_line_start(app, buffer, line_number); | |
indent.previous_line_indent = indent.current_indent; | |
Cpp_Token prev_token = {0}; | |
Cpp_Token token = {0}; | |
if (token_ptr < tokens.tokens + tokens.count){ | |
token = *token_ptr; | |
} | |
// Back up and consume this token too IF it is a scope opener. | |
if (token.type == CPP_TOKEN_BRACE_OPEN || token.type == CPP_TOKEN_BRACKET_OPEN){ | |
--token_ptr; | |
} | |
// LOOP OVER TOKENS | |
for (;;){ | |
if (line_number >= line_end){ | |
break; | |
} | |
prev_token = token; | |
++token_ptr; | |
if (token_ptr < tokens.tokens + tokens.count){ | |
token = *token_ptr; | |
} | |
else{ | |
token.type = CPP_TOKEN_EOF; | |
token.start = buffer->size; | |
token.flags = 0; | |
} | |
for (;token.start >= next_line_start_pos && line_number < line_end;){ | |
next_line_start_pos = buffer_get_line_start(app, buffer, line_number + 1); | |
int32_t this_indent = 0; | |
int32_t previous_indent = indent.previous_line_indent; | |
int32_t this_line_start = buffer_get_line_start(app, buffer, line_number); | |
int32_t next_line_start = next_line_start_pos; | |
bool32 did_multi_line_behavior = false; | |
// NOTE(allen): Check for multi-line tokens | |
if (prev_token.start <= this_line_start && prev_token.start + prev_token.size > this_line_start){ | |
if (prev_token.type == CPP_TOKEN_COMMENT || prev_token.type == CPP_TOKEN_STRING_CONSTANT){ | |
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, this_line_start, tab_width); | |
if (exact_align){ | |
this_indent = indent.previous_comment_indent; | |
} | |
else{ | |
if (hard_start.all_whitespace){ | |
this_indent = previous_indent; | |
} | |
else{ | |
int32_t line_pos = hard_start.char_pos - this_line_start; | |
this_indent = line_pos + indent.comment_shift; | |
if (this_indent < 0){ | |
this_indent = 0; | |
} | |
} | |
} | |
if (!hard_start.all_whitespace){ | |
if (line_number >= line_start){ | |
indent.previous_comment_indent = this_indent; | |
} | |
else{ | |
indent.previous_comment_indent = hard_start.indent_pos; | |
} | |
} | |
did_multi_line_behavior = true; | |
} | |
} | |
if (!did_multi_line_behavior){ | |
this_indent = indent.current_indent; | |
if (token.start < next_line_start){ | |
if (token.flags & CPP_TFLAG_PP_DIRECTIVE){ | |
this_indent = 0; | |
} | |
else{ | |
switch (token.type){ | |
case CPP_TOKEN_BRACKET_CLOSE: this_indent -= tab_width; break; | |
case CPP_TOKEN_BRACE_CLOSE: this_indent -= tab_width; break; | |
case CPP_TOKEN_BRACE_OPEN: break; | |
default: | |
if (indent.current_indent > 0){ | |
bool32 statement_complete = false; | |
Cpp_Token *prev_usable_token_ptr = token_ptr - 1; | |
Cpp_Token prev_usable_token = {0}; | |
if (prev_usable_token_ptr >= tokens.tokens){ | |
prev_usable_token = *prev_usable_token_ptr; | |
} | |
// Scan backwards for the previous token that actually tells us about the statement. | |
bool32 has_prev_usable_token = true; | |
#define NotUsable(T) \ | |
(((T).flags&CPP_TFLAG_PP_BODY) || ((T).flags&CPP_TFLAG_PP_DIRECTIVE) || ((T).type == CPP_TOKEN_COMMENT)) | |
if (NotUsable(prev_usable_token)){ | |
has_prev_usable_token = false; | |
for (--prev_usable_token_ptr; | |
prev_usable_token_ptr >= tokens.tokens; | |
--prev_usable_token_ptr){ | |
prev_usable_token = *prev_usable_token_ptr; | |
if (!NotUsable(prev_usable_token)){ | |
has_prev_usable_token = true; | |
break; | |
} | |
} | |
} | |
#undef NotUsable | |
if (!has_prev_usable_token){ | |
statement_complete = true; | |
} | |
else{ | |
if (prev_usable_token.type == CPP_TOKEN_BRACKET_OPEN || | |
prev_usable_token.type == CPP_TOKEN_BRACE_OPEN || | |
prev_usable_token.type == CPP_TOKEN_BRACE_CLOSE || | |
prev_usable_token.type == CPP_TOKEN_SEMICOLON || | |
prev_usable_token.type == CPP_TOKEN_COLON || | |
prev_usable_token.type == CPP_TOKEN_COMMA || | |
(tld_golang_indentation && ( // NOTE: TLD modifications begin here | |
prev_usable_token.type == CPP_TOKEN_KEY_CONTROL_FLOW || | |
prev_usable_token.type == CPP_TOKEN_BOOLEAN_CONSTANT || | |
prev_usable_token.type == CPP_TOKEN_STRING_CONSTANT || | |
prev_usable_token.type == CPP_TOKEN_IDENTIFIER || | |
prev_usable_token.type == CPP_TOKEN_INTEGER_CONSTANT || | |
prev_usable_token.type == CPP_TOKEN_FLOATING_CONSTANT || | |
prev_usable_token.type == CPP_TOKEN_CHARACTER_CONSTANT || | |
prev_usable_token.type == CPP_TOKEN_PARENTHESE_CLOSE || | |
prev_usable_token.type == CPP_TOKEN_BRACKET_CLOSE))){ | |
// NOTE: TLD modification ends here | |
statement_complete = true; | |
} | |
} | |
if (!statement_complete){ | |
this_indent += tab_width; | |
} | |
} | |
} | |
} | |
} | |
if (this_indent < 0) this_indent = 0; | |
} | |
if (indent.paren_nesting > 0){ | |
if (prev_token.type != CPP_TOKEN_PARENTHESE_OPEN){ | |
int32_t level = indent.paren_nesting-1; | |
if (level >= ArrayCount(indent.paren_anchor_indent)){ | |
level = ArrayCount(indent.paren_anchor_indent)-1; | |
} | |
this_indent = indent.paren_anchor_indent[level]; | |
} | |
} | |
// Rebase the paren anchor if the first token | |
// after the open paren is on the next line. | |
if (indent.paren_nesting > 0){ | |
if (prev_token.type == CPP_TOKEN_PARENTHESE_OPEN){ | |
int32_t level = indent.paren_nesting-1; | |
if (level >= ArrayCount(indent.paren_anchor_indent)){ | |
level = ArrayCount(indent.paren_anchor_indent)-1; | |
} | |
indent.paren_anchor_indent[level] = this_indent; | |
} | |
} | |
if (line_number >= line_start){ | |
indent_marks[line_number] = this_indent; | |
} | |
++line_number; | |
indent.previous_line_indent = this_indent; | |
} | |
// Update indent state. | |
switch (token.type){ | |
case CPP_TOKEN_BRACKET_OPEN: indent.current_indent += tab_width; break; | |
case CPP_TOKEN_BRACKET_CLOSE: indent.current_indent -= tab_width; break; | |
case CPP_TOKEN_BRACE_OPEN: indent.current_indent += tab_width; break; | |
case CPP_TOKEN_BRACE_CLOSE: indent.current_indent -= tab_width; break; | |
case CPP_TOKEN_COMMENT: | |
{ | |
int32_t line = buffer_get_line_number(app, buffer, token.start); | |
int32_t start = buffer_get_line_start(app, buffer, line); | |
indent.comment_shift = (indent.current_indent - (token.start - start)); | |
indent.previous_comment_indent = (token.start - start); | |
}break; | |
case CPP_TOKEN_PARENTHESE_OPEN: | |
{ | |
if (!(token.flags & CPP_TFLAG_PP_BODY)){ | |
if (indent.paren_nesting < ArrayCount(indent.paren_anchor_indent)){ | |
int32_t line = buffer_get_line_number(app, buffer, token.start); | |
int32_t start = buffer_get_line_start(app, buffer, line); | |
int32_t char_pos = token.start - start; | |
Hard_Start_Result hard_start = buffer_find_hard_start(app, buffer, start, tab_width); | |
int32_t line_pos = hard_start.char_pos - start; | |
indent.paren_anchor_indent[indent.paren_nesting] = char_pos - line_pos + indent.previous_line_indent + 1; | |
} | |
++indent.paren_nesting; | |
} | |
}break; | |
case CPP_TOKEN_PARENTHESE_CLOSE: | |
{ | |
if (!(token.flags & CPP_TFLAG_PP_BODY)){ | |
if (indent.paren_nesting > 0){ | |
--indent.paren_nesting; | |
} | |
} | |
}break; | |
} | |
} | |
} | |
// Unshift the indent_marks array. | |
indent_marks += line_start; | |
return(indent_marks); | |
} | |
// ... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************************************************************** | |
Author: Tristan Dannenberg | |
Notice: No warranty is offered or implied; use this code at your own risk. | |
******************************************************************************* | |
LICENSE | |
This software is dual-licensed to the public domain and under the following | |
license: you are granted a perpetual, irrevocable license to copy, modify, | |
publish, and distribute this file as you see fit. | |
******************************************************************************* | |
This file provides a parse context for golang syntax highlighting. | |
******************************************************************************/ | |
#if !defined(FTLD_LANGUAGE_GO_HPP) | |
#define FTLD_LANGUAGE_GO_HPP | |
static Parse_Context_ID tld_parse_context_language_golang; | |
#define PSAT(s, t) {s, sizeof(s)-1, t} | |
static void | |
tld_init_language_golang(Application_Links *app){ | |
if (tld_parse_context_language_golang != 0) return; | |
Parser_String_And_Type kw[] = { | |
PSAT("true", CPP_TOKEN_BOOLEAN_CONSTANT), | |
PSAT("false", CPP_TOKEN_BOOLEAN_CONSTANT), | |
// NOTE: Not a _boolean_ constant, obviously, but a keyword literal that | |
// should be highlighted and influence indentationo as such. | |
PSAT("nil", CPP_TOKEN_BOOLEAN_CONSTANT), | |
// NOTE: Some keywords can be statements in their own right. We'll designate | |
// those as CPP_TOKEN_KEY_CONTROL_FLOW, and all others as CPP_TOKEN_KEY_OTHER. | |
// | |
// This may not necessarily reflect their use in the language, but the indenter | |
// needs to be able to tell the two apart. | |
PSAT("continue", CPP_TOKEN_KEY_CONTROL_FLOW), | |
PSAT("break", CPP_TOKEN_KEY_CONTROL_FLOW), | |
PSAT("fallthrough", CPP_TOKEN_KEY_CONTROL_FLOW), | |
PSAT("return", CPP_TOKEN_KEY_CONTROL_FLOW), | |
PSAT("case", CPP_TOKEN_KEY_OTHER), | |
PSAT("chan", CPP_TOKEN_KEY_OTHER), | |
PSAT("const", CPP_TOKEN_KEY_OTHER), | |
PSAT("default", CPP_TOKEN_KEY_OTHER), | |
PSAT("defer", CPP_TOKEN_KEY_OTHER), | |
PSAT("else", CPP_TOKEN_KEY_OTHER), | |
PSAT("for", CPP_TOKEN_KEY_OTHER), | |
PSAT("func", CPP_TOKEN_KEY_OTHER), | |
PSAT("go", CPP_TOKEN_KEY_OTHER), | |
PSAT("goto", CPP_TOKEN_KEY_OTHER), | |
PSAT("if", CPP_TOKEN_KEY_OTHER), | |
PSAT("import", CPP_TOKEN_KEY_OTHER), | |
PSAT("interface", CPP_TOKEN_KEY_OTHER), | |
PSAT("map", CPP_TOKEN_KEY_OTHER), | |
PSAT("package", CPP_TOKEN_KEY_OTHER), | |
PSAT("range", CPP_TOKEN_KEY_OTHER), | |
PSAT("select", CPP_TOKEN_KEY_OTHER), | |
PSAT("struct", CPP_TOKEN_KEY_OTHER), | |
PSAT("switch", CPP_TOKEN_KEY_OTHER), | |
PSAT("type", CPP_TOKEN_KEY_OTHER), | |
PSAT("var", CPP_TOKEN_KEY_OTHER), | |
}; | |
tld_parse_context_language_golang = create_parse_context(app, kw, ArrayCount(kw), 0, 0); | |
} | |
#undef PSAT | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@ClaudioBarros I wonder if you have managed to implement it? I have 4coder 4.0.30 and so far I've figured that 4tld_language_go.h indeed belongs in the languages folder, and that it should be included in 4coder_default_hooks.cpp with the other languages' headers, and the function tld_init_language_golang called and parse_context_id set in the default_file_settings hook, like so:
.go has to be included in treat_as_code in your config.4coder for that to work.
I think you should also copy the "TLD" notes in this gist's 4coder_auto_indent.cpp to the get_indentation_marks function in your own 4coder_auto_indent.cpp but that doesn't work because tld_parse_context_language_golang is not available in that scope. I'm guessing that it has something to do with the fact that this code is 2 years old.