Closed wopox1337 closed 1 year ago
for future installAMXX.ts
:
AMXModX:
Stable
builds: https://www.amxmodx.org/amxxdrop/1.9/Dev
builds: https://www.amxmodx.org/amxxdrop/1.10/Hello!
I am favorable to the idea, but I have a few questions to help me decide which approach would be ideal:
.sp
instead of .sma
, how well does my extension work? I have zero experience with AMXModX.✅ All the syntax highlighting functionality works fine, except for ctrchar, which in amxmodx defaults to '^'
(not '\'
like in sourcepawn). And it doesn't break the highlighting in any way.
✅ The parser successfully retrieves function data from amxmodx/include/*.inc
about all basic functions as well as constants.
✅ The syntax highlighting in *.inc
files also works fine.
✔️ The tag with the construction ...
- does not define as a type. (corrected by me in attached .tmLanguage
)
Do you mean separately from sourcepawn
?
I unfortunately don't have enough free time to support a separate LSP, on Rust, I doubt the community can help with that at the moment. (there is a stagnation in developer activity and interest for GoldSrc, but that's not surprising).
Yes, technically it would be right to separate, however, given the circumstances, I don't see a more adequate outcome than integrating a stagnant AMXXPawn (not updated by developers) to your project.
Helping with the development and integration of a TypeScript backend is much easier than Rust (in my opinion). Therefore, more people will be able to help support the project, however, I could be wrong about that.
Specifically, I - do not have enough experience in Rust to do support at this time. However, would be able to help with integration to existing TypeScript code. I understand the importance of separating the LSP and developing it in a high-performance programming language like Rust, but "what we have is what we have".
Given all the screenshots in 1, it seems that the extension could easily support AMXModX, so that's great.
Regarding 2 and 3 and maintainability, you are entirely right if we separate the projects, it's likely to get abandoned.
Here is what I propose:
I prefer to finish my migration of sourcepawn_lsp first, and then deploy this new VSCode extension amxmodx-vscode
.
What do you think?
Migrating to the Rust LSP is a great solution. Rust is better suited for demanding tasks like `tree-sitter' and features related to auto complete, go to definition, or documentation on hover.
Adding amxxpawn
support mode to sourcepawn_LSP for the "evolved" sourcepawn (from amxxpawn) - seems more than reasonable, for at root have similar structures, visual similarity.
Creating a separate extension with SP_LSP support (amxxpawn mode), and implementing "VSCode goodies" on the frontend of the VSCode extension is a good idea. JS (TS) is not complicated, for support of features like 'load compiler from site', even more convenient.
In simple words, I agree with your solutions completely.
Great! I will do my best to implement this after I am done migrating to the sourcepawn_lsp.
On the other hand, having an abandoned amxxpawn extension would be just as bad as implementing the same functionality on two extensions that are literally "working on the same thing". The new syntax can hardly be considered a 'major change'.
In terms of supporting an extension that is not the most popular, it would be easier to make amxxpawn support in one extension. Make a simple setup with a pawn revision adapter (GoldSrc: amxxpawn, Source: sourcepawn, optional SA:MP: pawno).
They all have very similar syntax, differing only in the revision of one programming language and in essence have little difference.
Settings in VSCode can be overridden at the project level, which will be handy for customization.
It looks harder to implement, but will be much easier to support later.
This way a single VSCode extension will have more reach, and as a consequence, more interest and possibly more support from the community. ╰(°▽°)╯
P.S: The LSP is definitely left on Rust as an external solution, which can function even outside of VSCode.
Moving this here: https://github.com/Sarrus1/amxxpawn-vscode
What do you want to see added to the extension?
I suggest adding support for AMXXPawn. The syntax is 95% similar to SourcePawn of the old syntax version.
I am attaching a slightly corrected tmLanguage for AMXXPawn (instead of the terrible) and can provide a Pull Request to add support.
For a start, just adding support for opening
.sma
files with your extension would be nice.How would it help you?
There is no need to create a separate extension for AMXXPawn, which will not find support because of the lack of community and author activity.
The existing extension (https://github.com/rsKliPPy/amxxpawn-language) is long abandoned by the author, has many bugs, which will not be fixed, unfortunately...
How often would you use this feature?
The AMXXPawn community would appreciate "you" taking a little functionality like AMXXPawn support "under the wing". <3
I am attaching the corrected (there are some minor problems, but not critical) file
.tmLanguage
amxxpawn.tmLanguage.json
It is based on `sourcepawn.tmLanguage.json` with minor corrections. ```JSON { "$schema":"https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "name":"AMXXPawn", "scopeName":"source.amxxpawn", "patterns":[ { "include":"#line_continuation_character" }, { "include":"#literals" }, { "include":"#comments" }, { "include":"#operators" }, { "include":"#preproc" }, { "comment":"type cast", "match":"(\\w+)\\:\\s*(\\w+)", "captures":{ "1":{ "patterns":[ { "include":"#type" } ] }, "2":{ "patterns":[ { "include":"#literals" }, { "include":"#variable_name" } ] } } }, { "comment":"Scope access", "match":"(\\w+)\\:\\:(\\w*)", "captures":{ "1":{ "patterns":[ { "include":"#type_name" } ] }, "2":{ "patterns":[ { "include":"#variable_name" } ] } } }, { "comment":"Control statements", "name":"keyword.control.statement.amxxpawn", "match":"\\b(?:if|else|for|while|do|switch|case|default|return|break|goto|continue)\\b" }, { "include":"#function-declaration" }, { "include":"#other-keywords" }, { "include":"#enum" }, { "include":"#variable-declaration" }, { "include":"#function-call" }, { "match":"\\b(\\w+)\\b", "captures":{ "1":{ "patterns":[ { "include":"#variable_name" } ] } } } ], "repository":{ "enum":{ "begin":"(enum)\\s+(?:(\\w+(?:\\:)?)?(?:\\s*(\\([^\\(]*\\)))?)?", "beginCaptures":{ "1":{ "patterns":[ { "include":"#keywords" } ] }, "2":{ "patterns":[ { "include":"#type_name" } ] }, "3":{ "patterns":[ { "include":"#literals" } ] } }, "end":"(?<=\\})", "patterns":[ { "include":"#literals" }, { "include":"#comments" }, { "include":"#preproc" }, { "match":"(\\w+)", "captures":{ "1":{ "patterns":[ { "include":"#variable_name" } ] } } } ] }, "function-call":{ "comment":"Function call", "match":"\\b([A-Za-z_][A-Za-z0-9_]*)\\s*\\(", "captures":{ "1":{ "name":"entity.name.function.function_call.amxxpawn" } } }, "other-keywords":{ "comment":"other-keywords", "name":"keyword.amxxpawn", "match":"\\b(?:forward|native|public|const|stock|sizeof|tagof|operator|static)\\b" }, "parameters":{ "patterns":[ { "include":"#keywords" }, { "include":"#literals" }, { "include":"#parameter-declaration" } ] }, "array-indexed-access":{ "patterns":[ { "match":"\\[([^\\]]+)\\]", "captures":{ "1":{ "patterns":[ { "include":"#literals" }, { "include":"#other-keywords" }, { "include":"#function-call" }, { "include":"#variable_name" } ] } } } ] }, "parameter-declaration":{ "patterns":[ { "match":"(?:(\\w+)\\s*\\:\\s*)?(\\w+|\\.{3})\\s*((?:\\[[^\\]]*\\]\\s*)+)?", "captures":{ "1":{ "patterns":[ { "include":"#type" } ] }, "2":{ "patterns":[ { "include":"#variable_name" } ] }, "3":{ "patterns":[ { "include":"#array-indexed-access" } ] } } } ] }, "type":{ "patterns":[ { "match":"(_|bool|any|Float)|(\\w+)", "captures":{ "1":{ "name":"storage.type.built-in.primitive.amxxpawn" }, "2":{ "patterns":[ { "include":"#type_name" } ] } } } ] }, "function-declaration":{ "patterns":[ { "begin":"(?:(stock|public|static)\\s+)?(?:(native|forward)\\s+)?(?:(\\w+)\\:)?\\s*([a-zA-Z_]\\w*)\\(", "beginCaptures":{ "1":{ "patterns":[ { "include":"#keywords" } ] }, "2":{ "patterns":[ { "include":"#keywords" } ] }, "3":{ "patterns":[ { "include":"#type" } ] }, "4":{ "name":"entity.name.function.amxxpawn" } }, "end":"\\)", "patterns":[ { "include":"#parameters" }, { "include":"#comments" }, { "include":"#preproc" } ] } ] }, "operators":{ "patterns":[ { "name":"keyword.operator.amxxpawn", "match":"%|&|\\*|/(?!\\*|/)|\\+|\\-|~|=|<|>|!|\\||\\?|:|\\^" } ] }, "variable-declaration":{ "patterns":[ { "match":"(?:(stock|public)\\s+)?((?:(?:const|static)\\s+)*)(new)\\s+(?:(\\w+)\\:\\s*)?(\\w+)(\\s*(?:\\[[^\\]]*\\]\\s*)*)", "captures":{ "1":{ "patterns":[ { "include":"#keywords" } ] }, "2":{ "patterns":[ { "include":"#keywords" } ] }, "3":{ "patterns":[ { "include":"#keywords" } ] }, "4":{ "patterns":[ { "include":"#type" } ] }, "5":{ "patterns":[ { "include":"#variable_name" } ] }, "6":{ "patterns":[ { "include":"#array-indexed-access" } ] } } } ] }, "keywords":{ "patterns":[ { "match":"\\b(public|stock)\\b", "name":"keyword.visibility.amxxpawn" }, { "match":"\\b(const|static|native|forward)\\b", "name":"keyword.storage_class.amxxpawn" }, { "match":"\\b(new)\\b", "name":"keyword.variable_declarator.amxxpawn" }, { "match":"\\b(enum)\\b", "name":"keyword.enum.amxxpawn" } ] }, "literals":{ "patterns":[ { "include":"#boolean-literal" }, { "include":"#null-literal" }, { "include":"#numeric-literal" }, { "include":"#string-literal" }, { "include":"#other-literal" } ] }, "boolean-literal":{ "patterns":[ { "match":"\\b(?:true|false)\\b", "name":"constant.language.boolean.amxxpawn" } ] }, "null-literal":{ "patterns":[ { "match":"\\bnull\\b", "name":"constant.language.amxxpawn" } ] }, "other-literal":{ "patterns":[ { "match":"\\b(?:EOS,cellbits,cellmin,cellmax,charmin,charmax,ucharmax,__Pawn,__LINE__,debug)\\b", "name":"constant.language.amxxpawn" } ] }, "numeric-literal":{ "patterns":[ { "comment":"Float literal", "match":"[0-9]+\\.[0-9]+", "name":"constant.numeric.float.amxxpawn" }, { "comment":"Binary literal", "match":"\\b0b[0-1]+\\b", "name":"constant.numeric.amxxpawn" }, { "comment":"Octodecimal literal", "match":"\\b0o[0-7]+\\b", "name":"constant.numeric.amxxpawn" }, { "comment":"Hexadecimal literal", "match":"\\b(0x(?:(?:(?:[0-9a-fA-F]{2}_?)+)|(?:[0-9a-fA-F]+)))\\b", "name":"constant.numeric.amxxpawn" }, { "comment":"Integer literal", "match":"\\b((?:\\d|_)+)\\b", "name":"constant.numeric.integer.amxxpawn" }, { "comment":"Invalid literal", "match":"\\b\\d+\\w+\\b", "name":"invalid.illegal.constant.amxxpawn" } ] }, "string-literal":{ "patterns":[ { "begin":"\"", "beginCaptures":{ "0":{ "name":"punctuation.definition.string.begin.amxxpawn" } }, "end":"(\")|((?:[^\\\\\\n])$)", "endCaptures":{ "1":{ "name":"punctuation.definition.string.end.amxxpawn" }, "2":{ "name":"invalid.illegal.newline.amxxpawn" } }, "name":"string.quoted.double.amxxpawn", "patterns":[ { "include":"#string_escaped_char" }, { "include":"#string_format_char" }, { "include":"#string_placeholder" }, { "include":"#line_continuation_character" } ] }, { "begin":"'", "beginCaptures":{ "0":{ "name":"punctuation.definition.string.begin.amxxpawn" } }, "end":"(\\')|((?:[^\\\\\\n])$)", "endCaptures":{ "1":{ "name":"punctuation.definition.string.end.amxxpawn" }, "2":{ "name":"invalid.illegal.newline.amxxpawn" } }, "name":"string.quoted.single.c", "patterns":[ { "include":"#string_escaped_char" }, { "include":"#string_format_char" }, { "include":"#string_placeholder" }, { "include":"#line_continuation_character" } ] } ] }, "line_continuation_character":{ "patterns":[ { "match":"(\\\\)\\n", "captures":{ "1":{ "name":"constant.character.escape.line-continuation.amxxpawn" } } } ] }, "string_escaped_char":{ "patterns":[ { "match":"\\\\(?:[abefnrt'\"\\\\]|(?:x[a-zA-Z0-9]{0,2}|\\d+);?)", "name":"constant.character.escape.amxxpawn" }, { "match":"\\\\.", "name":"invalid.illegal.unknown-escape.amxxpawn" } ] }, "string_format_char":{ "name":"constant.character.format.amxxpawn", "match":"%(?:a|A|b|B|c|C|d|D|e|F|g|G|h|H|I|j|m|M|n|i|p|r|R|S|t|T|u|U|V|u|w|W|x|X|y|Y|z|Z|f|L|N|s|T|t|%|(?:\\d+)?\\.?\\d*(?:b|d|i|u|f|s|X|x))" }, "type_name":{ "patterns":[ { "match":"\\b\\d\\b", "name":"constant.numeric.integer.amxxpawn" }, { "match":"[a-zA-Z_]\\w*", "name":"support.type.core.amxxpawn" }, { "match":"([0-9])(\\w*)", "captures":{ "1":{ "name":"invalid.illegal.constant.amxxpawn" }, "2":{ "name":"support.type.core.amxxpawn" } } } ] }, "variable_name":{ "patterns":[ { "match":"\\b\\d\\b", "name":"constant.numeric.integer.amxxpawn" }, { "match":"[a-zA-Z_]\\w*", "name":"variable.amxxpawn" }, { "match":"([0-9])(\\w*)", "captures":{ "1":{ "name":"invalid.illegal.constant.amxxpawn" }, "2":{ "name":"variable.amxxpawn" } } } ] }, "preproc":{ "patterns":[ { "match":"(\\#include|\\#tryinclude)\\s*((?:\\<|\").+(?:\\>|\"))", "name":"meta.include.amxxpawn", "captures":{ "1":{ "name":"keyword.control.amxxpawn" }, "2":{ "name":"string.amxxpawn" } } }, { "match":"(\\#pragma)\\s+(.+?(?=//))", "name":"meta.pragma.line-comment.amxxpawn", "captures":{ "1":{ "name":"keyword.control.pragma.amxxpawn" }, "2":{ "name":"entity.other.attribute-name.amxxpawn" } } }, { "match":"(\\#pragma)\\s+(deprecated)(.*)", "name":"meta.pragma.deprecated.amxxpawn", "captures":{ "1":{ "name":"keyword.control.pragma.amxxpawn" }, "2":{ "name":"entity.other.attribute-name.amxxpawn" }, "3":{ "name":"string.deprecated.amxxpawn" } } }, { "match":"(\\#pragma)\\s+([A-Za-z _0-9]+)", "name":"meta.pragma.block-comment.amxxpawn", "captures":{ "1":{ "name":"keyword.control.pragma.amxxpawn" }, "2":{ "name":"entity.other.attribute-name.amxxpawn" } } }, { "match":"(\\#define)\\s*(\\w*)", "name":"meta.define.amxxpawn", "captures":{ "1":{ "name":"keyword.control.define.amxxpawn" }, "2":{ "name":"meta.preprocessor.macro.amxxpawn" } } }, { "match":"(\\#undef)\\s*(\\w*)", "name":"meta.undef.amxxpawn", "captures":{ "1":{ "name":"keyword.control.undef.amxxpawn" }, "2":{ "name":"meta.preprocessor.macro.amxxpawn" } } }, { "comment":"Preprocessor warning and error with trailing comment", "match":"(#\\b(?:warning|error)\\b)\\s*(.+?)(?=/(?:/|\\*))", "name":"meta.undef.amxxpawn", "captures":{ "1":{ "name":"keyword.control.misc.amxxpawn" }, "2":{ "name":"string.warning.amxxpawn" } } }, { "comment":"Preprocessor warning and error", "match":"(#\\b(?:warning|error)\\b)\\s*(.*)", "name":"meta.undef.amxxpawn", "captures":{ "1":{ "name":"keyword.control.misc.amxxpawn" }, "2":{ "name":"string.warning.amxxpawn" } } }, { "comment":"Preprocessor keywords", "match":"#\\b(if|else|endif|emit|deprecated|undef|endinput|endscript|assert|define|file)\\b\\s*", "name":"keyword.control.misc.amxxpawn" }, { "comment":"Preprocessor defined", "match":"(defined)\\s+([A-Za-z_]\\w*)", "captures":{ "1":{ "name":"meta.preprocessor.conditional.amxxpawn" }, "2":{ "name":"meta.preprocessor.macro.amxxpawn" } } } ] }, "comments":{ "patterns":[ { "match":"\\/\\/.*", "name":"comment.amxxpawn" }, { "begin":"/\\*", "captures":{ "0":{ "name":"comment.amxxpawn" } }, "end":"\\*/", "name":"comment.block.amxxpawn" } ] } } } ```also
amxxpawn.snippets.json
```JSON { "for loop": { "prefix": "for", "body": [ "for (new ${1|i,client,player|} = ${2:0}; $1 <= ${3:MaxClients}; $1++)", "{", "\t${4:}", "}" ], "description": "for loop" }, "while loop": { "prefix": "while", "body": ["while (${1:})", "{", "\t${2:}", "}"] }, "do while loop": { "prefix": "do", "body": ["do", "{", "\t${2:}", "}", "while(${1:})"] }, "if statement": { "prefix": "if", "body": ["if (${1:})", "{", "\t${2:}", "}"], "description": "if statement" }, "else statement": { "prefix": "else", "body": ["else", "{", "\t${1:}", "}"], "description": "else statement" }, "if else statement": { "prefix": "else if", "body": ["else if (${1:})", "{", "\t${2:}", "}"], "description": "else if statement" }, "include statement": { "prefix": "#include", "body": ["#include "], "description": "include" }, "pragma": { "prefix": "#pragma", "body": [ "#pragma ${1|amxlimit,codepage,compress,ctrlchar,deprecated,dynamic,library,reqlib,reqclass,loadlib,explib,expclass,defclasslib,reqlib,reqclass,loadlib,explib,expclass,defclasslib,pack,rational,semicolon,tabsize,align,unused,showstackusageinfo|}" ], "description": "pragma" }, "define": { "prefix": "#define", "body": ["#define ${1:defineName} ${2:defineValue}"], "description": "define" }, "template": { "prefix": "!!template", "body": [ "#include