├── .no-sublime-package
├── util
├── .gitignore
├── test_expansion.py
└── qvvars.py
├── bin
├── dart.exe
├── inqlik.snapshot
└── inqlik.bat
├── .gitignore
├── Snippets
├── DROP FIELD.sane.sublime-snippet
├── DROP TABLE.sane.sublime-snippet
├── RENAME FIELD.sane.sublime-snippet
├── RENAME TABLE.sane.sublime-snippet
└── NEW_QLIKVIEW_VARIABLE.sane.sublime-snippet
├── QlikView-vars.sublime-build
├── QlikView variables.sublime-build
├── Settings
├── FormatNum.sublime-macro
├── QlikView variables file.sublime-settings
├── QlikView script.sublime-settings
├── QlikView variables.sublime-completions
├── Default (Windows).sublime-keymap
├── QlikView GUI only.sublime-completions
├── QlikView script only.sublime-completions
├── Main.sublime-menu
├── test.json
└── QlikView script.sublime-completions
├── Syntax
├── ExpressionSection.tmPreferences
├── TabSymbol.tmPreferences
├── TableSymbol.tmPreferences
├── SoubroutineSymbol.tmPreferences
├── VariableSymbol.tmPreferences
├── ExpressionSymbol.tmPreferences
├── QlikView-reload-log.YAML-tmLanguage
├── Comments (QlikView).tmPreferences
├── QlikView-reload-log.tmLanguage
├── QlikView variables file.YAML-tmLanguage
├── QlikView variables file.tmLanguage
├── QlikView script.YAML-tmLanguage
└── QlikView script.tmLanguage
├── qvw_log_viewer.py
├── new_etl_module.py
├── qvw_open_log.py
├── qlikview_goto_file.py
├── qlikview_goto_definition.py
├── qvw_load.py
├── CHANGELOG.md
├── qvd_viewer.py
├── README.md
└── qlickview_vars.py
/.no-sublime-package:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/util/.gitignore:
--------------------------------------------------------------------------------
1 | /*.pyc
2 |
--------------------------------------------------------------------------------
/bin/dart.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inqlik/inqlik-tools/HEAD/bin/dart.exe
--------------------------------------------------------------------------------
/bin/inqlik.snapshot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inqlik/inqlik-tools/HEAD/bin/inqlik.snapshot
--------------------------------------------------------------------------------
/bin/inqlik.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | SET BINDIR=%~dp0
3 | "%BINDIR%dart.exe" "%BINDIR%inqlik.snapshot" %*
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /*.tmPreferences.cache
2 | /*.tmLanguage.cache
3 | /*.sane-snippet
4 | /*.pyc
5 | /package-metadata.json
--------------------------------------------------------------------------------
/Snippets/DROP FIELD.sane.sublime-snippet:
--------------------------------------------------------------------------------
1 | DROP FIELDdrop fieldsource.qvs
2 |
3 |
--------------------------------------------------------------------------------
/Snippets/DROP TABLE.sane.sublime-snippet:
--------------------------------------------------------------------------------
1 | DROP TABLEdrop tablesource.qvs
2 |
3 |
--------------------------------------------------------------------------------
/Snippets/RENAME FIELD.sane.sublime-snippet:
--------------------------------------------------------------------------------
1 | RENAME FIELDrename fieldsource.qvs
2 |
3 |
--------------------------------------------------------------------------------
/Snippets/RENAME TABLE.sane.sublime-snippet:
--------------------------------------------------------------------------------
1 | RENAME TABLErename tablesource.qvs
2 |
3 |
--------------------------------------------------------------------------------
/QlikView-vars.sublime-build:
--------------------------------------------------------------------------------
1 | {
2 | "target": "qlikview_variables_export",
3 | "selector": "source.qlikview-vars",
4 | "variants": [
5 | {
6 | "name": "Run",
7 | "target": "qlikview_variables_export",
8 | "commandVariant": "simple"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/Snippets/NEW_QLIKVIEW_VARIABLE.sane.sublime-snippet:
--------------------------------------------------------------------------------
1 | New QlikView Expression (YAML)---source.qlikview-vars
2 |
8 |
--------------------------------------------------------------------------------
/QlikView variables.sublime-build:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": ["inqlik.bat", "exp","$file"],
3 | "encoding": "utf8",
4 | "file_regex": "^>+ Parse error. File: \"(...*?)\", line: ([0-9]*)",
5 | "selector": "source.qlikview-vars",
6 | "variants": [
7 | {
8 | "name": "Run",
9 | "cmd": ["inqlik.bat", "exp","$file"],
10 | }
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/Settings/FormatNum.sublime-macro:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "args": null,
4 | "command": "copy"
5 | },
6 | {
7 | "args":
8 | {
9 | "characters": "Money"
10 | },
11 | "command": "insert"
12 | },
13 | {
14 | "args":
15 | {
16 | "contents": "($0)"
17 | },
18 | "command": "insert_snippet"
19 | },
20 | {
21 | "args": null,
22 | "command": "paste"
23 | },
24 | {
25 | "args":
26 | {
27 | "characters": ",'# ##0,00'"
28 | },
29 | "command": "insert"
30 | }
31 | ]
32 |
--------------------------------------------------------------------------------
/Syntax/ExpressionSection.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Expression Section
7 | scope
8 | source.qlikview-vars meta.name.section.qlikview-vars
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 |
14 |
15 | uuid
16 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f3201
17 |
18 |
--------------------------------------------------------------------------------
/Syntax/TabSymbol.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Tab
7 | scope
8 | source.qvs meta.tab.qvs
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 | symbolTransformation
14 | s/.*/$0/
15 |
16 | uuid
17 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f3203
18 |
19 |
--------------------------------------------------------------------------------
/Syntax/TableSymbol.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Tables
7 | scope
8 | source.qvs entity.name.type.table.qvs
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 | symbolTransformation
14 | s/.*/ $0 \(Table\)/
15 |
16 | uuid
17 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f3201
18 |
19 |
--------------------------------------------------------------------------------
/Syntax/SoubroutineSymbol.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Subroutine
7 | scope
8 | source.qvs entity.name.type.subroutine.qvs
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 | symbolTransformation
14 | s/.*/$0 \(SUB\)/
15 |
16 | uuid
17 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f3202
18 |
19 |
--------------------------------------------------------------------------------
/Syntax/VariableSymbol.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Variable
7 | scope
8 | source.qvs entity.name.type.variable.qvs
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 | symbolTransformation
14 | s/.*/ $0 \(Var\)/
15 |
16 | uuid
17 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f320f
18 |
19 |
--------------------------------------------------------------------------------
/Syntax/ExpressionSymbol.tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Symbol List: Expression
7 | scope
8 | source.qlikview-vars entity.name.type.expression.qlikview-vars
9 | settings
10 |
11 | showInSymbolList
12 | 1
13 | symbolTransformation
14 | s/.*/ $0/
15 |
16 | uuid
17 | c32ba3e2-4f2f-4ecf-922a-5b92ba7f3200
18 |
19 |
--------------------------------------------------------------------------------
/Settings/QlikView variables file.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | "separator":".",
3 | "output_mode": "CSV",
4 | "expand_variables": false,
5 | "mappings": {
6 | "set": "SET",
7 | "let": "LET",
8 | "label": "Label",
9 | "comment": "Comment",
10 | "backgroundColor": "backgroundColor",
11 | "fontColor": "FontColor",
12 | "textFormat": "TextFormat",
13 | "enableCondition":"EnableCondition",
14 | "showCondition":"ShowCondition",
15 | "sortBy":"SortBy",
16 | "visualCueUpper":"VisualCueUpper",
17 | "visualCueLower":"VisualCueLower",
18 | "symbol":"Symbol",
19 | "thousandSymbol":"ThousandSymbol",
20 | "millionSymbol":"MillionSymbol",
21 | "billionSymbol":"BillionSymbol"
22 | }
23 | }
--------------------------------------------------------------------------------
/util/test_expansion.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from qvvars import *
3 | class TestExpand(unittest.TestCase):
4 |
5 | # def setUp(self):
6 | # self.seq = range(10)
7 |
8 | def test_readerDummmy(self):
9 | reader = QvVarFileReader({})
10 | reader.parse_content('')
11 |
12 |
13 | # # should raise an exception for an immutable sequence
14 | # self.assertRaises(TypeError, random.shuffle, (1,2,3))
15 |
16 | # def test_choice(self):
17 | # element = random.choice(self.seq)
18 | # self.assertTrue(element in self.seq)
19 |
20 | # def test_sample(self):
21 | # with self.assertRaises(ValueError):
22 | # random.sample(self.seq, 20)
23 | # for element in random.sample(self.seq, 5):
24 | # self.assertTrue(element in self.seq)
25 |
26 | def testExpansion(content):
27 | reader = QvVarFileReader({})
28 | reader.parsedContent(content)
29 |
30 |
31 |
32 | if __name__ == '__main__':
33 | unittest.main()
--------------------------------------------------------------------------------
/Settings/QlikView script.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | // For internal use
3 | "use_infovizion": false,
4 | "qv_executable": "c:\\Program Files\\QlikView\\qv.exe",
5 | // If set to false, Open qvw file and Reload qvw file command would run by internal python script
6 | // If set to true they would use inqlik command line application (inqlik CLI)
7 | "qv_script_use_cli": false,
8 | // Use QlikView script syntax checker from inqlik CLI (operative only when "qv_script_use_cli": true)
9 | "qv_script_check_syntax": false,
10 | // Valid options are
11 | // - "check": Check syntax of qvs file and print out found errors
12 | // - "check_and_reload": Check syntax, reload qvw file if errors not found
13 | // - "force_reload": Check syntax, reload qvw file even if errors found
14 | "qv_script_check_syntax_mode": "check_and_reload",
15 | // Implicit include file (use it for example to declare predefined variables of QlikView Deployment Framework)
16 | "qv_script_check_syntax_impicit_include_file": "default_inqlude.qvs",
17 | }
--------------------------------------------------------------------------------
/Syntax/QlikView-reload-log.YAML-tmLanguage:
--------------------------------------------------------------------------------
1 | # [PackageDev] target_format: plist, ext: tmLanguage
2 | name: QlikView reload log file
3 | scopeName: source.qvw.log
4 | fileTypes: [qvw.log]
5 | uuid: 6b77dc03-7003-41f4-a9f6-287849f88d4a
6 |
7 | patterns:
8 | - include: '#assignment'
9 | - include: '#tableIdentifiers'
10 | - include: '#subroutine'
11 | - include: '#log_line'
12 |
13 | repository:
14 | log_line:
15 | patterns:
16 | - name: meta.line.qvw.log
17 | begin: ^
18 | end: $
19 | patterns:
20 | - include: source.qvs
21 | assignment:
22 | patterns:
23 | - match: ^\s*([LlSs][Ee][Tt])\s+((\w|\.)+)\s*=
24 | captures:
25 | '1': {name: keyword.control.qvs}
26 | tableIdentifiers:
27 | patterns:
28 | - name: support.constant.qvs
29 | match: ^(\s)*(\w+):(\s)*$
30 | captures:
31 | '2': {name: support.constant.qvs}
32 | subroutine:
33 | patterns:
34 | - match: ^\s*([Ss][Uu][Bb])\s+((?:\w|\.)+)
35 | captures:
36 | '1': {name: keyword.control.qvs}
37 | '2': {name: support.class}
--------------------------------------------------------------------------------
/Syntax/Comments (QlikView).tmPreferences:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | name
6 | Comments
7 | scope
8 | source.qvs
9 | settings
10 |
11 | shellVariables
12 |
13 |
14 | name
15 | TM_COMMENT_START
16 | value
17 | //
18 |
19 |
20 | name
21 | TM_COMMENT_START_2
22 | value
23 | /*
24 |
25 |
26 | name
27 | TM_COMMENT_END_2
28 | value
29 | */
30 |
31 |
32 | name
33 | TM_COMMENT_DISABLE_INDENT_2
34 | value
35 | yes
36 |
37 |
38 |
39 | uuid
40 | 4f4b122d-bd00-4458-81e6-9e51be9f7b81
41 |
42 |
43 |
--------------------------------------------------------------------------------
/Settings/QlikView variables.sublime-completions:
--------------------------------------------------------------------------------
1 | {
2 | "scope": "meta.newtag.qlikview-vars" ,
3 |
4 | "completions":
5 | [
6 | {"trigger": "comment:", "contents": "comment: $0"},
7 | {"trigger": "label:", "contents": "label: $0"},
8 | {"trigger": "definition:", "contents": "definition: $0"},
9 | {"trigger": "backgroundColor:", "contents": "backgroundColor: $0"},
10 | {"trigger": "tag:", "contents": "tag: $0"},
11 | {"trigger": "fontColor:", "contents": "fontColor: $0"},
12 | {"trigger": "textFormat:", "contents": "textFormat: $0"},
13 | {"trigger": "macro:", "contents": "macro: $0"},
14 | {"trigger": "description:", "contents": "description: $0"},
15 | {"trigger": "enableCondition:", "contents": "enableCondition: $0"},
16 | {"trigger": "showCondition:", "contents": "showCondition: $0"},
17 | {"trigger": "sortBy:", "contents": "sortBy: $0"},
18 | {"trigger": "visualCueUpper:", "contents": "visualCueUpper: $0"},
19 | {"trigger": "visualCueUpper:", "contents": "visualCueUpper: $0"},
20 | {"trigger": "visualCueUpper:", "contents": "visualCueUpper: $0"},
21 | {"trigger": "visualCueUpper:", "contents": "visualCueUpper: $0"},
22 | {"trigger": "visualCueLower:", "contents": "visualCueLower: $0"}
23 | ]
24 | }
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Settings/Default (Windows).sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | {"keys": ["ctrl+shift+l"], "command": "qlikview_open_log",
3 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvs" }]},
4 | {"keys": ["ctrl+shift+l"], "command": "qlikview_transform_log",
5 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvw.log" }]},
6 | {"keys": ["ctrl+shift+s"], "command": "qlikview_variables_export",
7 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qlikview-vars" }]},
8 | {"keys": ["f12"], "command": "qlikview_goto_definition",
9 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvs"}]},
10 | {"keys": ["f12"], "command": "qlikview_goto_definition",
11 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvw.log"}]},
12 | {"keys": ["ctrl+f12"], "command": "qlikview_goto_file",
13 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvs"}]},
14 | {"keys": ["ctrl+shift+b"], "command": "qlikview_reload","args": {"commandVariant": "open"},
15 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvs"}]},
16 | {"keys": ["f7"], "command": "qlikview_reload",
17 | "context": [{ "key": "selector", "operator": "equal", "operand": "source.qvs"}]}
18 |
19 | ]
20 |
--------------------------------------------------------------------------------
/Settings/QlikView GUI only.sublime-completions:
--------------------------------------------------------------------------------
1 | {
2 | "scope": "meta.expression.qlikview-vars" ,
3 | "completions":
4 | [
5 | {"trigger": "GetActiveSheetID", "contents": "GetActiveSheetID()$0"},
6 | {"trigger": "GetCurrentField", "contents": "GetCurrentField(${1:groupname})$0"},
7 | {"trigger": "GetFieldSelections", "contents": "GetFieldSelections('${1:fieldName}',${2:','},${3:6})$0"},
8 | {"trigger": "GetSelectedCount", "contents": "GetSelectedCount('${1:fieldName}')$0"},
9 | {"trigger": "GetPossibleCount", "contents": "GetPossibleCount('${1:fieldName}')$0"},
10 | {"trigger": "GetExcludedCount", "contents": "GetExcludedCount('${1:fieldName}')$0"},
11 | {"trigger": "GetAlternativeCount", "contents": "GetAlternativeCount('${1:fieldName}')$0"},
12 | {"trigger": "GetNotSelectedCount", "contents": "GetNotSelectedCount('${1:fieldName}')$0"},
13 | {"trigger": "GetExtendedProperty", "contents": "GetExtendedProperty('${1:name}','${2:objectID}')$0"},
14 | {"trigger": "StateName", "contents": "StateName()$0"},
15 | {"trigger": "DocumentTitle", "contents": "DocumentTitle()$0"},
16 | {"trigger": "GetObjectField", "contents": "GetObjectField('${1:index}')$0"},
17 | {"trigger": "GetCurrentSelections", "contents": "GetCurrentSelections(${1:chr(13)},${2:':'},${3:','},${4:6})$0"}
18 | ]
19 | }
--------------------------------------------------------------------------------
/qvw_log_viewer.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import sublime
3 | import sublime_plugin
4 | import os
5 | import collections
6 | import sys
7 | import re
8 | class QlikviewTransformLogCommand(sublime_plugin.TextCommand):
9 | moduleSettings = None
10 | edit = None
11 | path = ''
12 | timer = None
13 | def run(self, edit):
14 | self.edit = edit
15 | self.path = self.view.file_name()
16 | self.transform()
17 |
18 | def transform(self):
19 | view = self.view
20 | edit = self.edit
21 | view.set_read_only(False)
22 | view.set_scratch(True)
23 | txt = view.substr(sublime.Region(0,view.size()))
24 | view.erase(edit,sublime.Region(0,view.size()))
25 | trace_mode = False
26 | for line in txt.splitlines():
27 | if trace_mode:
28 | line = re.sub(r'^(\s*\d+[/.-]\d+[/.-]\d{4} \d+:\d+:\d+( AM| PM)?: .{4})',r'//>> \1',line)
29 | trace_mode = False
30 | else:
31 | line = re.sub(r'^\s*\d+[/.-]\d+[/.-]\d{4} \d+:\d+:\d+( AM| PM)?:\s+\d{4}','',line)
32 | if re.match(r'^\s*TRACE',line,flags=re.IGNORECASE):
33 | trace_mode = True
34 | print(line)
35 | line = re.sub(r'^(\s*\d+[/.-]\d+[/.-]\d{4} \d+:\d+:\d+( AM| PM)?: {4})',r'//>> \1',line)
36 | self.addLine(line)
37 |
38 | def addLine(self,line):
39 | self.view.insert(self.edit, self.view.size(), line+'\n')
40 | def is_enabled(self):
41 | return sublime.active_window().active_view().file_name().upper().endswith('.QVW.LOG')
--------------------------------------------------------------------------------
/new_etl_module.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import sublime
3 | import sublime_plugin
4 | import re
5 | import os
6 | class NewEtlModuleCommand(sublime_plugin.WindowCommand):
7 | fileName = ''
8 | qvwTemplate = ''
9 | shebang = ''
10 | def run(self, commandVariant=None):
11 | view = self.window.active_view()
12 | qv_executable = view.settings().get("qv_executable","c:\\Program Files\\QlikView\\qv.exe")
13 | firstLine = view.substr(view.line(0))
14 | self.fileName = view.file_name()
15 | baseName, ext = os.path.splitext(os.path.basename(self.fileName))
16 | if ext != '.qvs':
17 | sublime.error_message('New ETL module command shoud be invoked from within QlikView script')
18 | return
19 | qvwFile = ''
20 | testFile = ''
21 | print (firstLine)
22 | if re.match(r'\/\/\#\!', firstLine):
23 | self.shebang = re.sub(r'\/\/\#\!','',firstLine)
24 | testFile = os.path.abspath(os.path.join(os.path.dirname(self.fileName),self.shebang,'_NewFileTemplate.qvw'))
25 | if os.path.exists(testFile):
26 | self.qvwTemplate = testFile
27 | if self.qvwTemplate == '':
28 | sublime.error_message('File not found: %s' % self.qvwTemplate)
29 | return
30 | self.window.show_input_panel('Enter name for new module:','NewModule',self.createModule,None,None)
31 | def createModule(self,moduleName):
32 | targetQvwFile = os.path.abspath(os.path.join(os.path.dirname(self.fileName),self.shebang,moduleName + '.qvw'))
33 | if os.path.exists(targetQvwFile):
34 | sublime.error_message('File %s already exists' % targetQvwFile)
35 | return
36 | self.window.run_command("exec", { "cmd": ["cmd","/C","copy",self.qvwTemplate,targetQvwFile]})
37 | targetQvsFile = os.path.join(os.path.dirname(self.fileName),moduleName+'.qvs')
38 | self.window.run_command("exec", { "cmd": ["cmd","/C","copy",self.fileName,targetQvsFile]})
39 | self.window.open_file(targetQvsFile)
40 |
--------------------------------------------------------------------------------
/qvw_open_log.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import sublime
3 | import sublime_plugin
4 | import os
5 | import re
6 | class QlikviewOpenLogCommand(sublime_plugin.WindowCommand):
7 | view = None
8 | def run(self, commandVariant=None):
9 | view = self.window.active_view()
10 | useInfovizion = view.settings().get("use_infovizion",False)
11 | firstLine = view.substr(view.line(0))
12 | fileName = view.file_name()
13 | if useInfovizion:
14 | baseName, ext = os.path.splitext(os.path.basename(fileName))
15 | testFile = os.path.join(os.path.dirname(fileName),'logs',baseName +'.qvw.log')
16 | if not os.path.exists(testFile):
17 | print('Log file not found: %s' % testFile)
18 | sublime.error_message('Log file not found: %s' % testFile)
19 | else:
20 | self.view = self.window.open_file(testFile)
21 | else:
22 | baseName, ext = os.path.splitext(os.path.basename(fileName))
23 | testFile = ''
24 | if re.match(r'\/\/\#\!', firstLine):
25 | shebang = re.sub(r'\/\/\#\!','',firstLine)
26 | if shebang.endswith('.qvw'):
27 | testFile = shebang
28 | if os.path.exists(shebang):
29 | testFile = shebang + '.log'
30 | else:
31 | testFile = os.path.abspath(os.path.join(os.path.dirname(fileName),shebang,baseName + '.qvw.log'))
32 | else:
33 | testFile = os.path.join(os.path.dirname(fileName),baseName +'.qvw.log')
34 | if not os.path.exists(testFile):
35 | print('Log file not found: %s' % testFile)
36 | sublime.error_message('Log file not found: %s' % testFile)
37 | else:
38 | self.view = self.window.open_file(testFile)
39 | self.transform()
40 | def transform(self):
41 | if self.view.is_loading():
42 | sublime.set_timeout_async(self.transform,100)
43 | else:
44 | self.view.run_command('qlikview_transform_log')
45 | def is_enabled(self):
46 | return self.window.active_view().file_name().upper().endswith('.QVS')
--------------------------------------------------------------------------------
/qlikview_goto_file.py:
--------------------------------------------------------------------------------
1 | import sublime, sublime_plugin
2 | import os
3 | from fnmatch import fnmatch
4 |
5 | class QlikviewGotoFile(sublime_plugin.WindowCommand):
6 | def find_files(self, fileName):
7 | result = set([])
8 | if os.path.isfile(fileName):
9 | return [fileName]
10 | for folder in sublime.active_window().folders():
11 | for root, dirs, files in os.walk(folder):
12 | for file in files:
13 | if file.upper().endswith(fileName.upper()):
14 | result.add(os.path.join(root, file))
15 | return list(result)
16 | def open_file(self,fileName):
17 | open_externally = False
18 | for gpat in sublime.active_window().active_view().settings().get("open_externally_patterns", []):
19 | if fnmatch(fileName, gpat):
20 | open_externally = True
21 | print(fileName)
22 | if open_externally:
23 | sublime.status_message("Opening file ...... " + fileName)
24 | os.startfile(fileName)
25 | sublime.status_message("")
26 | else:
27 | sublime.active_window().open_file(fileName)
28 | def run(self, fileName = None):
29 | print ('qlikview_goto_file');
30 | orig_sel = None
31 | v = self.window.active_view()
32 | if v:
33 | orig_sel = [r for r in v.sel()]
34 |
35 | if not fileName and not v:
36 | return
37 |
38 | if not fileName:
39 | pt = v.sel()[0]
40 |
41 | fileName = v.substr(v.expand_by_class(pt,
42 | sublime.CLASS_WORD_START | sublime.CLASS_WORD_END,
43 | "[]{}()<>:="))
44 | print('Find and open file %s' % fileName)
45 | fileName = fileName.strip('\\/');
46 | files = self.find_files(fileName)
47 | print (files)
48 | if len(files) == 0:
49 | sublime.status_message("Unable to find " + fileName)
50 | elif len(files) == 1:
51 | print('Opening')
52 | self.open_file(files[0])
53 | else:
54 | self.window.show_quick_panel(
55 | files,
56 | lambda x: self.open_file(files[x]))
57 |
--------------------------------------------------------------------------------
/Settings/QlikView script only.sublime-completions:
--------------------------------------------------------------------------------
1 | {
2 | "scope": "source.qvs" ,
3 | "completions":
4 | [
5 | {"trigger": "FileBasename", "contents": "FileBasename()$0"},
6 | {"trigger": "FileDir", "contents": "FileDir()$0"},
7 | {"trigger": "FileExtension", "contents": "FileExtension()$0"},
8 | {"trigger": "GetFolderPath", "contents": "GetFolderPath()$0"},
9 | {"trigger": "FileName", "contents": "FileName()$0"},
10 | {"trigger": "FilePath", "contents": "FilePath()$0"},
11 | {"trigger": "FileSize", "contents": "FileSize('${1:fileName}')$0"},
12 | {"trigger": "FileTime", "contents": "FileTime('${1:fileName}')$0"},
13 | {"trigger": "QvdCreateTime", "contents": "QvdCreateTime('${1:fileName}')$0"},
14 | {"trigger": "NoOfFields", "contents": "NoOfFields('${1:tableName}')$0"},
15 | {"trigger": "NoOfRows", "contents": "NoOfRows('${1:tableName}')$0"},
16 | {"trigger": "NoOfTables", "contents": "NoOfTables()$0"},
17 | {"trigger": "TableName", "contents": "TableName(${1:tableNumber})$0"},
18 | {"trigger": "QvdNoOfRecords", "contents": "QvdNoOfRecords('${1:fileName}')$0"},
19 | {"trigger": "QvdNoOfFields", "contents": "QvdNoOfFields('${1:fileName}')$0"},
20 | {"trigger": "QvdFieldName", "contents": "QvdFieldName('${1:fileName}','${2:fieldNo}')$0"},
21 | {"trigger": "Peek", "contents": "Peek('${1:fieldName}',${2:row}','${3:tableName}')$0"},
22 | {"trigger": "QvdTableName", "contents": "QvdTableName('${1:fileName}')$0"},
23 | {"trigger": "FieldName", "contents": "FieldName(${1:fieldNo},'${2:tableName}')$0"},
24 | {"trigger": "FieldNumber", "contents": "FieldNumber('${1:field}','${2:tableName}')$0"},
25 | {"trigger": "ConnectString", "contents": "ConnectString()$0"},
26 | {"trigger": "IsPartialReload", "contents": "IsPartialReload()$0"},
27 | {"trigger": "MsgBox", "contents": "MsgConnectString:msg}')$0"},
28 | {"trigger": "Attribute", "contents": "Attribute('${1:fileName}','${2:attributename}')$0"},
29 | {"trigger": "Input", "contents": "Input('${1:cue}','${2:caption}')$0"},
30 | {"trigger": "QV_SKIP_PARSING", "contents": "//#!QV_SKIP_PARSING"},
31 | {"trigger": "QV_TRACE_TABLES", "contents": "//#!QV_TRACE_TABLES"},
32 | {"trigger": "QV_SUPPRESS_ERROR", "contents": "//#!QV_SUPPRESS_ERROR"},
33 | {"trigger": "QV_TRACE_USER_VARIABLES", "contents": "//#!QV_TRACE_USER_VARIABLES"}
34 | ]
35 | }
--------------------------------------------------------------------------------
/Syntax/QlikView-reload-log.tmLanguage:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | fileTypes
6 |
7 | qvw.log
8 |
9 | name
10 | QlikView reload log file
11 | patterns
12 |
13 |
14 | include
15 | #assignment
16 |
17 |
18 | include
19 | #tableIdentifiers
20 |
21 |
22 | include
23 | #subroutine
24 |
25 |
26 | include
27 | #log_line
28 |
29 |
30 | repository
31 |
32 | assignment
33 |
34 | patterns
35 |
36 |
37 | captures
38 |
39 | 1
40 |
41 | name
42 | keyword.control.qvs
43 |
44 |
45 | match
46 | ^\s*([LlSs][Ee][Tt])\s+((\w|\.)+)\s*=
47 |
48 |
49 |
50 | log_line
51 |
52 | patterns
53 |
54 |
55 | begin
56 | ^
57 | end
58 | $
59 | name
60 | meta.line.qvw.log
61 | patterns
62 |
63 |
64 | include
65 | source.qvs
66 |
67 |
68 |
69 |
70 |
71 | subroutine
72 |
73 | patterns
74 |
75 |
76 | captures
77 |
78 | 1
79 |
80 | name
81 | keyword.control.qvs
82 |
83 | 2
84 |
85 | name
86 | support.class
87 |
88 |
89 | match
90 | ^\s*([Ss][Uu][Bb])\s+((?:\w|\.)+)
91 |
92 |
93 |
94 | tableIdentifiers
95 |
96 | patterns
97 |
98 |
99 | captures
100 |
101 | 2
102 |
103 | name
104 | support.constant.qvs
105 |
106 |
107 | match
108 | ^(\s)*(\w+):(\s)*$
109 | name
110 | support.constant.qvs
111 |
112 |
113 |
114 |
115 | scopeName
116 | source.qvw.log
117 | uuid
118 | 6b77dc03-7003-41f4-a9f6-287849f88d4a
119 |
120 |
121 |
--------------------------------------------------------------------------------
/Syntax/QlikView variables file.YAML-tmLanguage:
--------------------------------------------------------------------------------
1 | # [PackageDev] target_format: plist, ext: tmLanguage
2 | name: QlikView vars file
3 | fileTypes: [qlikview-vars]
4 |
5 | scopeName: source.qlikview-vars
6 |
7 | uuid: 6b77dc03-7003-41f4-a9f6-287849f88d5f
8 |
9 | patterns:
10 |
11 | - include: '#expressionName'
12 |
13 | - include: '#section'
14 |
15 | - include: '#yamlNewDocument'
16 |
17 | - include: '#expression'
18 |
19 | - include: '#expressionWithEqualSign'
20 |
21 | - include: '#expressionWithoutEqualSign'
22 |
23 | - include: '#simpleField'
24 |
25 | - include: '#def'
26 |
27 | - include: '#newtag'
28 |
29 | repository:
30 | def:
31 | patterns:
32 | - name: meta.expression.qlikview-vars
33 | begin: ^#define\s+
34 | beginCaptures:
35 | '0': {name: support.constant.qlikview-vars}
36 | end: ^(?=\S)
37 | endCaptures:
38 | '0': {name: support.constant.qlikview-vars}
39 | patterns:
40 | - include: source.qvs
41 |
42 | expression:
43 | patterns:
44 | - name: meta.expression.qlikview-vars
45 | begin: '^(definition|macro|condition|backgroundColor|fontColor|textFormat|enableCondition|showCondition|sortBy|visualCueUpper|visualCueLower|symbol|thousandSymbol|width|millionSymbol|billionSymbol|family|type|selectorLabel|format|calendar):'
46 | beginCaptures:
47 | '0': {name: support.constant.qlikview-vars}
48 | end: ^(?=\S)
49 | endCaptures:
50 | '0': {name: support.constant.qlikview-vars}
51 | patterns:
52 | - include: source.qvs
53 |
54 | expressionWithEqualSign:
55 | patterns:
56 | - name: meta.expression.qlikview-vars
57 | begin: ^(label|comment):\s*(?==)
58 | beginCaptures:
59 | '0': {name: support.constant.qlikview-vars}
60 | end: ^(?=\S)
61 | endCaptures:
62 | '0': {name: support.constant.qlikview-vars}
63 | patterns:
64 | - include: source.qvs
65 |
66 | expressionWithoutEqualSign:
67 | patterns:
68 | - name: string.single.quoted.qlikview-vars
69 | begin: '^(label|comment):'
70 | beginCaptures:
71 | '0': {name: support.constant.qlikview-vars}
72 | end: ^(?=\S)
73 | endCaptures:
74 | '0': {name: support.constant.qlikview-vars}
75 | newtag:
76 | patterns:
77 | - name: meta.newtag.qlikview-vars
78 | match: (^(\w)*(?!:))
79 |
80 | expressionName:
81 | patterns:
82 | - match: ^\s*(set|let):\s*(\w[\w_.]+)\s*$
83 | captures:
84 | '1': {name: support.constant.qlikview-vars}
85 | '2': {name: support.variable.qlikview-vars entity.name.type.expression.qlikview-vars}
86 |
87 | simpleField:
88 | patterns:
89 | - name: support.constant.qlikview-vars
90 | match: (^(\s)*(tag|description):(\s)*)
91 |
92 | yamlNewDocument:
93 | patterns:
94 | - name: support.constant.qlikview-vars
95 | match: ^---$
96 | section:
97 | patterns:
98 | - match: ^(#SECTION )\s*(.+)$
99 | captures:
100 | '1': {name: comment.line.double-dash.qlikview-vars}
101 | '2': {name: support.variable.qlikview-vars meta.name.section.qlikview-vars}
102 |
--------------------------------------------------------------------------------
/qlikview_goto_definition.py:
--------------------------------------------------------------------------------
1 | import sublime, sublime_plugin
2 |
3 | import sublime, sublime_plugin
4 |
5 | class QlikviewGotoDefinition(sublime_plugin.WindowCommand):
6 | def goto_location(self, l):
7 | fname, display_fname, rowcol = l
8 | row, col = rowcol
9 |
10 | v = self.window.open_file(fname + ":" + str(row) + ":" + str(col), sublime.ENCODED_POSITION)
11 |
12 | def select_entry(self, locations, idx, orig_view, orig_sel):
13 | if idx >= 0:
14 | self.goto_location(locations[idx])
15 | else:
16 | # TODO: restore sel
17 | if orig_view:
18 | self.window.focus_view(orig_view)
19 |
20 | def highlight_entry(self, locations, idx):
21 | fname, display_fname, rowcol = locations[idx]
22 | row, col = rowcol
23 |
24 | self.window.open_file(fname + ":" + str(row) + ":" + str(col),
25 | sublime.TRANSIENT | sublime.ENCODED_POSITION)
26 |
27 | def format_location(self, l):
28 | fname, display_fname, rowcol = l
29 | row, col = rowcol
30 |
31 | return display_fname + ":" + str(row)
32 |
33 | def lookup_symbol(self, symbol):
34 | index_locations = self.window.lookup_symbol_in_index(symbol)
35 | open_file_locations = self.window.lookup_symbol_in_open_files(symbol)
36 |
37 | def file_in_location_list(fname, locations):
38 | for l in locations:
39 | if l[0] == fname:
40 | return True
41 | return False;
42 |
43 | # Combine the two lists, overriding results in the index with results
44 | # from open files, while trying to preserve the order of the files in
45 | # the index.
46 | locations = []
47 | ofl_ignore = []
48 | for l in index_locations:
49 | if file_in_location_list(l[0], open_file_locations):
50 | if not file_in_location_list(l[0], ofl_ignore):
51 | for ofl in open_file_locations:
52 | if l[0] == ofl[0]:
53 | locations.append(ofl)
54 | ofl_ignore.append(ofl)
55 | else:
56 | locations.append(l)
57 |
58 | for ofl in open_file_locations:
59 | if not file_in_location_list(ofl[0], ofl_ignore):
60 | locations.append(ofl)
61 |
62 | return locations
63 |
64 | def run(self, symbol = None):
65 | orig_sel = None
66 | v = self.window.active_view()
67 | if v:
68 | orig_sel = [r for r in v.sel()]
69 |
70 | if not symbol and not v:
71 | return
72 |
73 | if not symbol:
74 | pt = v.sel()[0]
75 |
76 | symbol = v.substr(v.expand_by_class(pt,
77 | sublime.CLASS_WORD_START | sublime.CLASS_WORD_END,
78 | "[]{}()<>:="))
79 | locations = self.lookup_symbol(symbol)
80 |
81 | if len(locations) == 0:
82 | symbol = v.substr(v.word(pt))
83 | locations = self.lookup_symbol(symbol)
84 |
85 | else:
86 | locations = self.lookup_symbol(symbol)
87 |
88 | if len(locations) == 0:
89 | sublime.status_message("Unable to find " + symbol)
90 | elif len(locations) == 1:
91 | self.goto_location(locations[0])
92 | else:
93 | self.window.show_quick_panel(
94 | [self.format_location(l) for l in locations],
95 | lambda x: self.select_entry(locations, x, v, orig_sel),
96 | on_highlight = lambda x: self.highlight_entry(locations, x))
97 |
--------------------------------------------------------------------------------
/qvw_load.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import sublime
3 | import sublime_plugin
4 | import os
5 | import re
6 | class QlikviewReloadCommand(sublime_plugin.WindowCommand):
7 | def run(self, commandVariant=None):
8 | self.window.run_command('save')
9 | view = self.window.active_view()
10 | qv_executable = view.settings().get("qv_executable","c:\\Program Files\\QlikView\\qv.exe")
11 | useInfovizion = view.settings().get("use_infovizion",False)
12 | if view.settings().get('qv_script_use_cli') == True:
13 | self.runCli(view, qv_executable, commandVariant)
14 | else:
15 | if useInfovizion:
16 | self.runByInfovizion(view, commandVariant)
17 | else:
18 | self.runPython(view, qv_executable, commandVariant)
19 | def runPython(self, view, qv_executable, commandVariant=None):
20 | self.window.run_command('save')
21 | firstLine = view.substr(view.line(0))
22 | fileName = view.file_name()
23 | baseName, ext = os.path.splitext(os.path.basename(fileName))
24 | qvwFile = ''
25 | testFile = ''
26 | print (firstLine)
27 | if re.match(r'\/\/\#\!', firstLine):
28 | shebang = re.sub(r'\/\/\#\!','',firstLine)
29 | if shebang.endswith('.qvw'):
30 | testFile = shebang
31 | if os.path.exists(shebang):
32 | qvwFile = shebang
33 | else:
34 | testFile = os.path.abspath(os.path.join(os.path.dirname(fileName),shebang,baseName + '.qvw'))
35 | if os.path.exists(testFile):
36 | qvwFile = testFile
37 | else:
38 | testFile = os.path.join(os.path.dirname(fileName),baseName +'.qvw')
39 | if os.path.exists(testFile):
40 | qvwFile = testFile
41 | if qvwFile == '':
42 | sublime.error_message('File not found: %s' % testFile)
43 | else:
44 | sublime.status_message('Reloading file %s' % qvwFile)
45 | print("commandVariant", commandVariant)
46 | if commandVariant is None:
47 | self.window.run_command("exec", { "cmd": [qv_executable,"/R","/nodata","/Nosecurity",qvwFile]})
48 | else:
49 | self.window.run_command("exec", { "cmd": ["cmd","/C",qv_executable,qvwFile]})
50 | def runCli(self, view, qv_executable, commandVariant=None):
51 | file_regex = "^>* Parse error. File: \"(...*?)\", line: ([0-9]*)"
52 | scriptPath = "%s\\Inqlik-Tools\\bin\\inqlik.bat" % sublime.packages_path()
53 | fileName = view.file_name()
54 | if commandVariant is None:
55 | cliCommand = 'just_reload'
56 | include = 'default_include.qvs'
57 | if view.settings().get('qv_script_check_syntax') == True:
58 | cliCommand = view.settings().get('qv_script_check_syntax_mode','force_reload')
59 | include = view.settings().get('qv_script_check_syntax_impicit_include_file','default_inqlude.qvs')
60 | self.window.run_command("exec", { "file_regex": file_regex, "cmd": [scriptPath,"qvs", "--command=%s" % cliCommand, fileName]})
61 | print([scriptPath,"qvs", "--command=%s" % cliCommand, fileName])
62 | else:
63 | self.window.run_command("exec", { "file_regex": file_regex, "cmd": [scriptPath,"qvs", "--command=open",fileName]})
64 | def runByInfovizion(self, view, commandVariant=None):
65 | file_regex = "^File: (.+), line: (.+)"
66 | executable = "c:\\Programs\\infovizion\\bin\\dart"
67 | snapshot = "c:\\Programs\\infovizion\\bin\\infovizion.dart.snapshot"
68 | work_dir = "c:\\Programs\\infovizion\\"
69 | fileName = view.file_name()
70 | if view.settings().get('qv_script_check_syntax') == True:
71 | dummy = True
72 | self.window.run_command("exec", { "working_dir": work_dir, "file_regex": file_regex, "cmd": [executable, snapshot,"sense","app-reload", "--script", fileName]})
73 |
74 |
75 |
--------------------------------------------------------------------------------
/Settings/Main.sublime-menu:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "children": [
4 | {
5 | "children": [
6 | {
7 | "children": [
8 | {
9 | "command": "new_etl_module",
10 | "caption": "New ETL module"
11 | },
12 | {
13 | "command": "qlikview_open_log",
14 | "caption": "Open and reformat qvw.log file"
15 | },
16 | {
17 | "command": "qlikview_transform_log",
18 | "caption": "Reformat qvw.log file"
19 | },
20 | {
21 | "command": "qlikview_variables_export",
22 | "caption": "Expand variables and export file"
23 | }
24 | ],
25 | "id": "qlikview",
26 | "caption": "InQlik-Tools"
27 | }
28 | ],
29 | "id": "packages",
30 | "caption": "Packages"
31 | }
32 | ],
33 | "id": "tools"
34 | },
35 | {
36 | "children": [
37 | {
38 | "children": [
39 | {
40 | "children": [
41 | {
42 | "args": {
43 | "file": "${packages}/InQlik-Tools/README.md"
44 | },
45 | "command": "open_file",
46 | "caption": "README"
47 | },
48 | {
49 | "caption": "-"
50 | },
51 | {
52 | "args": {
53 | "file": "${packages}/Inqlik-Tools/Settings/QlikView variables file.sublime-settings"
54 | },
55 | "command": "open_file",
56 | "caption": "QlikView Variables file settings: Default"
57 | },
58 | {
59 | "args": {
60 | "file": "${packages}/User/QlikView variables file.sublime-settings"
61 | },
62 | "command": "open_file",
63 | "caption": "QlikView Variables file settings: User"
64 | },
65 | {
66 | "caption": "-"
67 | },
68 | {
69 | "args": {
70 | "file": "${packages}/Inqlik-Tools/Settings/QlikView script.sublime-settings"
71 | },
72 | "command": "open_file",
73 | "caption": "QlikView script settings: Default"
74 | },
75 | {
76 | "args": {
77 | "file": "${packages}/User/QlikView script.sublime-settings"
78 | },
79 | "command": "open_file",
80 | "caption": "QlikView script settings: User"
81 | },
82 | {
83 | "caption": "-"
84 | }
85 | ],
86 | "caption": "InQlik-Tools"
87 | }
88 | ],
89 | "mnemonic": "P",
90 | "id": "package-settings",
91 | "caption": "Package Settings"
92 | }
93 | ],
94 | "mnemonic": "n",
95 | "id": "preferences",
96 | "caption": "Preferences"
97 | }
98 | ]
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ###Changelog
2 |
3 | ####0.1.40
4 |
5 | - New Expression file export format: JSON. Additional attributes for Infovizion in-house Sense development process
6 |
7 | ####0.1.39
8 |
9 | - Autosave current QVS file before reloading. That imitate build system default behaviour
10 |
11 | ####0.1.38
12 |
13 | - Bugfix for syntax check. Temporarily not using `qv_script_check_syntax_impicit_include_file` setting
14 |
15 | ####0.1.37
16 |
17 | - Sublime Text in version 3080 introduced serious regression in default Build Systems behaviour. Default key binding `F7` and `Ctrl-Shift-B` currently not run alternative build tasks (`Reload` and `Open qvw file` in case if former build system for QVS files) but pops up some menu with some commmand variants. In this version I recover previous behaviour using basic syntax specific key-bindings. `F7` silently run `Reload` command. `Ctrl-Shift-B` run `Open qvw file` command as in previous revisions of ST3.
18 | - Plugin optionally can use `Inqlik CLI` command line utility for some tasks. That utility now shipped with package
19 | - `QlikView script settings` items added to `Package settings\Inqlik-Tools` menu.
20 | - QlikView script settings extended to provide options for using `Inqlik CLI` for `Reload` and `Open qvw file` tasks. `Reload` task can include check syntax phase
21 | - Inqlik CLI supports сustom file name in relative build paths. [See feature request](https://github.com/inqlik/inqlik-tools/issues/5)
22 | - Package settings defaults to using old python code for reload and open qvw file tasks
23 |
24 | ####0.1.36
25 |
26 | - Add build system for Expression files. Use external (Inqlik CLI) tool
27 |
28 | ####0.1.35
29 |
30 | - Bugfix for https://github.com/inqlik/inqlik-tools/issues/3
31 |
32 | ####0.1.34
33 |
34 | - Bugfix for https://github.com/inqlik/inqlik-tools/issues/2
35 |
36 |
37 | ####0.1.33
38 |
39 | - Permit unicode variable names. Again
40 |
41 | ####0.1.32
42 |
43 | - By default TAG column in QDF variables file filled with values from SECTION, it ca be overloaded by explicit tag: tag, Added completions for qvs parser directives. Bugfix for
44 |
45 | ####0.1.31
46 |
47 | - Bugfix for tabular csv export format for Expression Editor. Export format was erroneously named `CVS` both in README and in plugin code.
48 | Name for tabular csv format fixed and changed to `CSV`
49 |
50 | ####0.1.30
51 |
52 | - Some changes in auto-completion for functions
53 | - Added menu command and key combination for command `Expand variables and export file` in Expression editor
54 | - Plain QVS export format temporarily removed from Expression Editor.
55 | - `.no-sublime-package` file flag added to project. Packaged format sometimes lead to bugs.
56 |
57 | ####0.1.29
58 |
59 | - Added auto-completion for most functions with cues for parameters
60 |
61 | ####0.1.28
62 |
63 | - Bugfix in NewExpression snippet
64 |
65 | ####0.1.27
66 |
67 | - Bugfix in goto_files
68 |
69 | ####0.1.24
70 |
71 | - Tabular CSV format added for Expression Editor
72 |
73 | ####0.1.23
74 |
75 | - Bugfix to qvw.log files viewer
76 |
77 | ####0.1.22
78 |
79 | - Qvw.log file viewer added
80 | - Menu and keyboard (ctrl-shilt+l) commands for opening and reformat qvw.log files
81 |
82 | ####0.1.21
83 |
84 | - Package renamed to InQlik Tools
85 | - Tags names changed to lowercase camelCase format
86 | - Menu items for package preferences
87 | - Default settings for variable files
88 |
89 | ####0.1.20
90 |
91 | - Bugfix in error processing in variable files plugin
92 | - Additional tags in variable files plugin
93 |
94 | ####0.1.19
95 |
96 | - Symbols in qvs: suroutines, variables and table identifiers. Tabs are local symbols
97 | - Symbols in expression files: expression names and \#SECTION tags
98 |
99 | ####0.1.18
100 |
101 | - QVD Viewer plugin added. (ST3 only)
102 |
103 | ####0.1.17
104 |
105 | - Expression file plugin refactored
106 |
107 | ####0.1.16
108 |
109 | - qlikview_vars.py refactored
110 | - Syntax for qlikview-vars files changed
111 | - Support for most properties of qlikview expression added.
112 | - Settings for configuration of derived variable names
113 |
114 | ####0.1.15
115 |
116 | - Bugfix for relative paths in shebang for Build system. Tested in QlikView Deployment Framework environment
117 |
118 | ####0.1.14
119 |
120 | - Get rid of qvw_load.bat. Build system now runs custom-made command QlikviewReloadCommand. QlikView executable path can be changed in user settings
121 |
122 | ####0.1.13
123 |
124 | - qvw_load.bat fixed. Build system now works with qvs scripts encoded with UTF8 with BOM
125 |
126 | ####0.1.12
127 |
128 | - Readme sections for Build system usage and installation added
129 |
130 | ####0.1.11
131 |
132 | - Legacy syntax for expression files removed. Futher development will use QlikView variables files compatible with QlikView Deployment Framework
133 | - Build system added. Able to run batch reload of qvw file in same directory or explicitely set by shebang syntax
134 |
135 |
136 | ####0.1.10
137 |
138 | - Initial release for Package Control Channel
--------------------------------------------------------------------------------
/qvd_viewer.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import sublime
3 | import sublime_plugin
4 | import os
5 | import collections
6 | from xml.dom import minidom
7 | import sys
8 |
9 | class QvdField:
10 | fieldName = ''
11 | uniqValues = 0
12 | memoryUsage = 0
13 | class QvdTable:
14 | noOfRecords = 0
15 | tableName = ''
16 | creatorDoc = ''
17 | createdTime = ''
18 | fields = []
19 |
20 | class QlikviewQvdFileListener(sublime_plugin.EventListener):
21 |
22 | EXT_QLIKVIEW_QVD = ".QVD"
23 | def on_activated(self,view):
24 | if not self.is_ST3():
25 | return
26 | fn = view.file_name()
27 | if (fn is None):
28 | return
29 | if (fn.upper().endswith(self.EXT_QLIKVIEW_QVD)):
30 | view.run_command('qvd_viewer',{'cmd':''})
31 | def is_ST3(self):
32 | ''' check if ST3 based on python version '''
33 | version = sys.version_info
34 | if isinstance(version, tuple):
35 | version = version[0]
36 | elif getattr(version, 'major', None):
37 | version = version.major
38 | return (version >= 3)
39 |
40 | class QvdViewerCommand(sublime_plugin.TextCommand):
41 | moduleSettings = None
42 | edit = None
43 | path = ''
44 | def run(self, edit, cmd=''):
45 | self.edit = edit
46 | self.path = self.view.file_name()
47 | sublime.active_window().run_command('close')
48 | # view.run_command('close')
49 | self.view = sublime.active_window().new_file()
50 | view = self.view
51 | view.set_scratch(True)
52 | token = collections.deque()
53 | tokenMarker = collections.deque([b'<',b'/',b'Q',b'v',b'd',b'T',b'a',b'b',b'l',b'e',b'H',b'e',b'a',b'd',b'e',b'r',b'>'])
54 | token = collections.deque(tokenMarker)
55 | tokenStr = collections.deque()
56 | buff = collections.deque()
57 | n = 0
58 | headerFound = False
59 | with open(self.path, 'rb') as f:
60 | while True:
61 | char = f.read(1)
62 | n = n + 1
63 | if n > 100000:
64 | break
65 | if char =='':
66 | break
67 | buff.append(char)
68 | token.append(char)
69 | token.popleft()
70 | if token == tokenMarker:
71 | headerFound = True
72 | break
73 | if not headerFound:
74 | self.addLine('ERROR: QvdFile header have not been recognized')
75 | return
76 | buffString = b''.join(buff)
77 | xml = minidom.parseString(buffString)
78 | self.parseHeader(xml)
79 | def parseHeader(self, xml):
80 | table = QvdTable()
81 | table.fields = []
82 | table.tableName = self.getValue(xml,"TableName")
83 | table.noOfRecords = self.getValue(xml,"NoOfRecords")
84 | table.createdTime = self.getValue(xml,"CreateUtcTime")
85 | for fieldXml in xml.getElementsByTagName("QvdFieldHeader"):
86 | field = QvdField()
87 | field.fieldName = self.getValue(fieldXml,"FieldName")
88 | field.uniqValues = self.getValue(fieldXml,"NoOfSymbols")
89 | field.memoryUsage = self.getValue(fieldXml,"Length")
90 | field.fieldType = 'Number'
91 | if self.getValue(fieldXml,"NumberFormat/Type") == "UNKNOWN":
92 | field.fieldType = "String"
93 | table.fields.append(field)
94 | viewHeader = table.tableName + '.MD'
95 | self.addLine(viewHeader)
96 | self.addLine('---')
97 | self.addLine('')
98 | line = '%s records. QVD created at %s' % (table.noOfRecords,table.createdTime)
99 | self.addLine(line)
100 | self.addLine('')
101 | self.addLine('###Fields:')
102 | self.addLine('')
103 | for field in table.fields:
104 | line = "- **%s**. Unique values: %s, Memory usage: %s" % (field.fieldName, field.uniqValues, field.memoryUsage)
105 | self.addLine(line)
106 | self.addLine('')
107 | self.addLine('####Sample load statement:')
108 | self.addLine('')
109 | self.addLine('```QlikView')
110 | self.addLine('')
111 | self.addLine('LOAD')
112 | comma = ','
113 | for field in table.fields:
114 | if field.fieldName == table.fields[-1].fieldName:
115 | comma = ''
116 | self.addLine(' ' + field.fieldName + comma)
117 | self.addLine(' FROM [' + self.path+'] (QVD);')
118 | self.addLine('')
119 | self.addLine('```')
120 | self.closeOthers(viewHeader)
121 | def addLine(self,line):
122 | self.view.insert(self.edit, self.view.size(), line + '\n')
123 | def getValue(self,xml,tagName):
124 | nodeList = xml.getElementsByTagName(tagName)
125 | if len(nodeList) == 0:
126 | return ''
127 | tag = nodeList[0].toxml()
128 | xmlData=tag.replace('<'+tagName+'>','').replace(''+tagName+'>','')
129 | return xmlData
130 | def closeOthers(self,viewHeader):
131 | window = self.view.window()
132 | myId = self.view.id()
133 | for v in window.views():
134 | if v.id() == myId:
135 | continue
136 | l = v.line(sublime.Region(0,0))
137 | line = v.substr(l)
138 | if (line == viewHeader):
139 | window.focus_view(v)
140 | window.run_command('close')
141 | window.focus_view(self.view)
142 |
--------------------------------------------------------------------------------
/Settings/test.json:
--------------------------------------------------------------------------------
1 | {"trigger": "Acos", "contents": "Acos(${1:x})$0"},
2 | {"trigger": "AddMonths", "contents": "AddMonths(${1:startdate}, ${2:n})$0"},
3 | {"trigger: "Aggr", "contents": "Aggr(${1:expression}, ${2:dimension})$0"},
4 | {"trigger": "Alt", "contents": "Alt(${1:case1}, ${2:else})$0"},
5 | {"trigger": "ApplyMap", "contents": "ApplyMap('${1:mapname}', ${2:expr}, ${3:defaultexpr})$0"},
6 | {"trigger": "ARGB", "contents": "ARGB(${1:alpha}, ${2:e1}, ${3:e2}, ${4:e3})$0"},
7 | {"trigger": "Asin", "contents": "Asin(${1:x})$0"},
8 | {"trigger": "Atan", "contents": "Atan(${1:x})$0"},
9 | {"trigger": "Atan2", "contents": "Atan2(${1:x,}, ${2:y})$0"},
10 | {"trigger": "Autonumber", "contents": "Autonumber(${1:expression}, '${2:AutoID}')$0"},
11 | {"trigger": "AutonumberHash128", "contents": "AutonumberHash128(${1:expression})$0"},
12 | {"trigger": "AutonumberHash256", "contents": "AutonumberHash256(${1:expression})$0"},
13 | {"trigger": "Avg", "contents": "Avg(${1:expression})$0"},
14 | {"trigger": "Avg", "contents": "Avg(${1:expression})$0"},
15 | {"trigger": "BitCount", "contents": "BitCount(${1:x})$0"},
16 | {"trigger": "Ceil", "contents": "Ceil(${1:x})$0"},
17 | {"trigger": "Chr", "contents": "Chr(${1:n})$0"},
18 | {"trigger": "Combin", "contents": "Combin(${1:n1},${2:n2})$0"},
19 | {"trigger": "Concat", "contents": "Concat('${1:expression}', ${2:delimiter}, ${3:sort})$0"},
20 | {"trigger": "Cos", "contents": "Cos(${1:x})$0"},
21 | {"trigger": "Cosh", "contents": "Cosh(${1:x})$0"},
22 | {"trigger": "Count", "contents": "Count(${1:expression})$0"},
23 | {"trigger": "Div", "contents": "Div(${1:x1}, ${2:x2})$0"},
24 | {"trigger": "Even", "contents": "Even(x)(${1:x})$0"},
25 | {"trigger": "Exp", "contents": "Exp(${1:x})$0"},
26 | {"trigger": "Fabs", "contents": "Fabs(${1:x})$0"},
27 | {"trigger": "Fact", "contents": "Fact(${1:x})$0"},
28 | {"trigger": "FieldValueCount", "contents": "FieldValueCount('${1:fieldName}')$0"},
29 | {"trigger": "FirstSortedValue", "contents": "FirstSortedValue('${1:expression}', ${2:sort-weight}, ${3:n})$0"},
30 | {"trigger": "FirstValue", "contents": "FirstValue(${1:expression})$0"},
31 | {"trigger": "Floor", "contents": "Floor(${1:x})$0"},
32 | {"trigger": "FMod", "contents": "FMod(${1:x1},${2:x2})$0"},
33 | {"trigger": "frac", "contents": "frac(${1:x})$0"},
34 | {"trigger": "If", "contents": "If(${1:condition}, ${2:then}, ${3:else})$0"},
35 | {"trigger": "IterNo", "contents": "IterNo()$0"},
36 | {"trigger": "LastValue", "contents": "LastValue(${1:expression})$0"},
37 | {"trigger": "Left", "contents": "Left(${1:string}, ${2:n})$0"},
38 | {"trigger": "Log", "contents": "Log(${1:x})$0"},
39 | {"trigger": "Log10", "contents": "Log10(${1:x})$0"},
40 | {"trigger": "Lookup", "contents": "Lookup('${1:field_name}', '${2:match_field_name}', ${3:match_field_value},'${4:table_name}')$0"},
41 | {"trigger": "Max", "contents": "Max(${1:expression})$0"},
42 | {"trigger": "MaxString", "contents": "MaxString(${1:expression})$0"},
43 | {"trigger": "Min", "contents": "Min(${1:expression})$0"},
44 | {"trigger": "MinString", "contents": "MinString(${1:expression})$0"},
45 | {"trigger": "MissingCount", "contents": "MissingCount(${1:expression})$0"},
46 | {"trigger": "Mod", "contents": "Mod(${1:x1},${2:x2})$0"},
47 | {"trigger": "Mode", "contents": "Mode(${1:expression})$0"},
48 | {"trigger": "NullCount", "contents": "NullCount(${1:expression})$0"},
49 | {"trigger": "NumericCount", "contents": "NumericCount(${1:expression})$0"},
50 | {"trigger": "Odd", "contents": "Odd(${1:x})$0"},
51 | {"trigger": "Only", "contents": "Only(${1:expression})$0"},
52 | {"trigger": "Ord", "contents": "Ord(${1:str})$0"},
53 | {"trigger": "Permut", "contents": "Permut(${1:n1},${2:n2})$0"},
54 | {"trigger": "Pow", "contents": "Pow(${1:x}, ${2:y})$0"},
55 | {"trigger": "RangeAvg", "contents": "RangeAvg(${1:expr1}, ${2:expr2})$0"},
56 | {"trigger": "RangeCorrel", "contents": "RangeCorrel(${1:x-value}, ${2:y-value})$0"},
57 | {"trigger": "RangeCount", "contents": "RangeCount(${1:expr1}, ${2:expr2})$0"},
58 | {"trigger": "RangeFractile", "contents": "RangeFractile(${1:expr1}, ${2:expr2})$0"},
59 | {"trigger": "RangeKurtosis", "contents": "RangeKurtosis(${1:expr1}, ${2:expr2})$0"},
60 | {"trigger": "RangeMax", "contents": "RangeMax(${1:expr1}, ${2:expr2})$0"},
61 | {"trigger": "RangeMaxString", "contents": "RangeMaxString(${1:expr1}, ${2:expr2})$0"},
62 | {"trigger": "RangeMin", "contents": "RangeMin(${1:expr1}, ${2:expr2})$0"},
63 | {"trigger": "RangeMinString", "contents": "RangeMinString(${1:expr1}, ${2:expr2})$0"},
64 | {"trigger": "RangeMissingCount", "contents": "RangeMissingCount(${1:expr1}, ${2:expr2})$0"},
65 | {"trigger": "RangeMode", "contents": "RangeMode(${1:expr1}, ${2:expr2})$0"},
66 | {"trigger": "RangeNullCount", "contents": "RangeNullCount(${1:expr1}, ${2:expr2})$0"},
67 | {"trigger": "RangeNumericCount", "contents": "RangeNumericCount(${1:expr1}, ${2:expr2})$0"},
68 | {"trigger": "RangeOnly", "contents": "RangeOnly(${1:expr1}, ${2:expr2})$0"},
69 | {"trigger": "RangeSkew", "contents": "RangeSkew(${1:expr1}, ${2:expr2})$0"},
70 | {"trigger": "RangeStdev", "contents": "RangeStdev(${1:expr1}, ${2:expr2})$0"},
71 | {"trigger": "RangeSum", "contents": "RangeSum(${1:expr1}, ${2:expr2})$0"},
72 | {"trigger": "RangeTextCount", "contents": "RangeTextCount(${1:expr1}, ${2:expr2})$0"},
73 | {"trigger": "RecNo", "contents": "RecNo()$0"},
74 | {"trigger": "Right", "contents": "Right(${1:string}, ${2:n})$0"},
75 | {"trigger": "Round", "contents": "Round(${1:x})$0"},
76 | {"trigger": "RowNo", "contents": "RowNo()$0"},
77 | {"trigger": "Sign", "contents": "Sign(${1:x})$0"},
78 | {"trigger": "Sin", "contents": "Sin(${1:x})$0"},
79 | {"trigger": "Sinh", "contents": "Sinh(${1:x})$0"},
80 | {"trigger": "Sqr", "contents": "Sqr(${1:x})$0"},
81 | {"trigger": "Sqrt", "contents": "Sqrt(${1:x})$0"},
82 | {"trigger": "Sum", "contents": "Sum(${1:expression})$0"},
83 | {"trigger": "Tan", "contents": "Tan(${1:x})$0"},
84 | {"trigger": "Tanh", "contents": "Tanh(${1:x})$0"},
85 | {"trigger": "TextCount", "contents": "TextCount(${1:expression})$0"},
86 | {"trigger": "Chr", "contents": "Chr(${1:n})$0"},
87 | {"trigger": "FieldValueCount", "contents": "FieldValueCount('${1:fieldName}')$0"},
88 |
--------------------------------------------------------------------------------
/Syntax/QlikView variables file.tmLanguage:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | fileTypes
6 |
7 | qlikview-vars
8 |
9 | name
10 | QlikView vars file
11 | patterns
12 |
13 |
14 | include
15 | #expressionName
16 |
17 |
18 | include
19 | #section
20 |
21 |
22 | include
23 | #yamlNewDocument
24 |
25 |
26 | include
27 | #expression
28 |
29 |
30 | include
31 | #expressionWithEqualSign
32 |
33 |
34 | include
35 | #expressionWithoutEqualSign
36 |
37 |
38 | include
39 | #simpleField
40 |
41 |
42 | include
43 | #def
44 |
45 |
46 | include
47 | #newtag
48 |
49 |
50 | repository
51 |
52 | def
53 |
54 | patterns
55 |
56 |
57 | begin
58 | ^#define\s+
59 | beginCaptures
60 |
61 | 0
62 |
63 | name
64 | support.constant.qlikview-vars
65 |
66 |
67 | end
68 | ^(?=\S)
69 | endCaptures
70 |
71 | 0
72 |
73 | name
74 | support.constant.qlikview-vars
75 |
76 |
77 | name
78 | meta.expression.qlikview-vars
79 | patterns
80 |
81 |
82 | include
83 | source.qvs
84 |
85 |
86 |
87 |
88 |
89 | expression
90 |
91 | patterns
92 |
93 |
94 | begin
95 | ^(definition|macro|condition|backgroundColor|fontColor|textFormat|enableCondition|showCondition|sortBy|visualCueUpper|visualCueLower|width|symbol|thousandSymbol|millionSymbol|billionSymbol|family|type|selectorLabel|format|calendar):
96 | beginCaptures
97 |
98 | 0
99 |
100 | name
101 | support.constant.qlikview-vars
102 |
103 |
104 | end
105 | ^(?=\S)
106 | endCaptures
107 |
108 | 0
109 |
110 | name
111 | support.constant.qlikview-vars
112 |
113 |
114 | name
115 | meta.expression.qlikview-vars
116 | patterns
117 |
118 |
119 | include
120 | source.qvs
121 |
122 |
123 |
124 |
125 |
126 | expressionName
127 |
128 | patterns
129 |
130 |
131 | captures
132 |
133 | 1
134 |
135 | name
136 | support.constant.qlikview-vars
137 |
138 | 2
139 |
140 | name
141 | support.variable.qlikview-vars entity.name.type.expression.qlikview-vars
142 |
143 |
144 | match
145 | ^\s*(set|let):\s*(\w[\w_.]+)\s*$
146 |
147 |
148 |
149 | expressionWithEqualSign
150 |
151 | patterns
152 |
153 |
154 | begin
155 | ^(label|comment):\s*(?==)
156 | beginCaptures
157 |
158 | 0
159 |
160 | name
161 | support.constant.qlikview-vars
162 |
163 |
164 | end
165 | ^(?=\S)
166 | endCaptures
167 |
168 | 0
169 |
170 | name
171 | support.constant.qlikview-vars
172 |
173 |
174 | name
175 | meta.expression.qlikview-vars
176 | patterns
177 |
178 |
179 | include
180 | source.qvs
181 |
182 |
183 |
184 |
185 |
186 | expressionWithoutEqualSign
187 |
188 | patterns
189 |
190 |
191 | begin
192 | ^(label|comment):
193 | beginCaptures
194 |
195 | 0
196 |
197 | name
198 | support.constant.qlikview-vars
199 |
200 |
201 | end
202 | ^(?=\S)
203 | endCaptures
204 |
205 | 0
206 |
207 | name
208 | support.constant.qlikview-vars
209 |
210 |
211 | name
212 | string.single.quoted.qlikview-vars
213 |
214 |
215 |
216 | newtag
217 |
218 | patterns
219 |
220 |
221 | match
222 | (^(\w)*(?!:))
223 | name
224 | meta.newtag.qlikview-vars
225 |
226 |
227 |
228 | section
229 |
230 | patterns
231 |
232 |
233 | captures
234 |
235 | 1
236 |
237 | name
238 | comment.line.double-dash.qlikview-vars
239 |
240 | 2
241 |
242 | name
243 | support.variable.qlikview-vars meta.name.section.qlikview-vars
244 |
245 |
246 | match
247 | ^(#SECTION )\s*(.+)$
248 |
249 |
250 |
251 | simpleField
252 |
253 | patterns
254 |
255 |
256 | match
257 | (^(\s)*(tag|description):(\s)*)
258 | name
259 | support.constant.qlikview-vars
260 |
261 |
262 |
263 | yamlNewDocument
264 |
265 | patterns
266 |
267 |
268 | match
269 | ^---$
270 | name
271 | support.constant.qlikview-vars
272 |
273 |
274 |
275 |
276 | scopeName
277 | source.qlikview-vars
278 | uuid
279 | 6b77dc03-7003-41f4-a9f6-287849f88d5f
280 |
281 |
282 |
--------------------------------------------------------------------------------
/util/qvvars.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: UTF-8 -*-
2 | import os
3 | import re
4 | import xml.etree.ElementTree as etree
5 | import csv
6 | import sys
7 | import datetime
8 |
9 | class QvVarFileReader:
10 | ALLOWED_TAGS = ('Label','Comment', 'Definition','BackgroundColor','FontColor','TextFormat',
11 | 'Tag','Separator','#define', 'Macro','Description','EnableCondition',
12 | 'ShowCondition','SortBy','VisualCueUpper','VisualCueLower')
13 | FIELDS_TO_SKIP = ('Definition','Tag','SET','LET','command','name','separator','Macro','Description')
14 | NAME_MAP = {}
15 |
16 | line_template = re.compile(r'^(?P\w+?):\s*(?P.*)$')
17 | define_template = re.compile(r'^#define\s*(?P\S+)\s+(?P.*)$')
18 | param_template = re.compile(r'^\s*\-\s*(?P.*)$')
19 |
20 | linenum = 0
21 | defs = {}
22 | macro = []
23 | output = []
24 | define_directives = {}
25 | moduleSettings = None
26 | def __init__(self,moduleSettings):
27 | self.linenum = 0
28 | self.defs = {}
29 | self.macro = []
30 | self.output = []
31 | self.define_directives = {}
32 | self.moduleSettings = moduleSettings
33 |
34 | def put_row(self, key, value, command, comment, priority):
35 | self.output.append([command.upper(), key ,value, comment, priority])
36 | def parse_content(self,text):
37 | print('IN PARSE_CONTENT')
38 | self.NAME_MAP = {}
39 | mappings = self.moduleSettings.get('mappings',{})
40 | for tag in self.ALLOWED_TAGS:
41 | self.NAME_MAP[tag] = mappings.get(tag,tag);
42 | self.NAME_MAP['separator'] = self.moduleSettings.get('separator','.')
43 | expression = {}
44 | defs = {}
45 | define_directives = {}
46 | self.linenum = 0
47 | self.macro = []
48 | self.output = []
49 | def expand_macro():
50 | if defs.get(self.macro[0]) is None:
51 | raise SyntaxError('Parsing error: definition for macro `%s` is not found' % self.macro[0])
52 | result = defs[self.macro[0]]
53 | i = 1
54 | while i < len(self.macro):
55 | param = self.macro[i]
56 | subs = '$%s' % str(i)
57 | if not subs in result:
58 | print('macro',self.macro)
59 | raise SyntaxError('Parsing error: definition for macro `%s` does not contain substring %s' % (self.macro[0],subs))
60 | result = result.replace(subs,param)
61 | i = i + 1
62 | return result
63 | def init_expression():
64 | self.macro = []
65 | expression = {}
66 | def process_expression(exp):
67 | if exp == {}:
68 | return None
69 | if exp.get('name') is None:
70 | return'Parsing error: `name` property is absent'
71 | if exp['name'] in defs:
72 | return 'Parsing error: duplicate expression with name `%s`' % exp['name']
73 | if exp.get('Definition') is not None and exp.get('Macro') is not None:
74 | return 'Parsing error: Expression have defined both `definition` and `macro` property. Something one must be defined'
75 | if exp.get('Definition') is None:
76 | if exp.get('Macro') is None:
77 | return 'Parsing error: Expression `%s` have not defined `definition` or `macro` property' % exp['name']
78 | exp['Definition'] = expand_macro()
79 | local_def = exp['Definition']
80 | for k, v in define_directives.items():
81 | local_def = local_def.replace(k,v)
82 | exp['Definition'] = local_def
83 | defs[exp['name']] = exp['Definition']
84 | comment = exp.get('Description')
85 | tag = exp.get('Tag')
86 | command = exp.get('command')
87 | name = exp.get('name')
88 | self.put_row(name,expression['Definition'],command, comment, tag)
89 | for key in exp.keys():
90 | if key not in self.FIELDS_TO_SKIP:
91 | varName = '%s%s%s' % (name,self.NAME_MAP['separator'],self.NAME_MAP[key])
92 | self.put_row(varName,expression[key],'SET', '', tag)
93 | init_expression()
94 | return None
95 | def parse_val(text):
96 | if text == None:
97 | return ''
98 | return text.strip()
99 | def parse_define_directive(line):
100 | match = self.define_template.match(line)
101 | if match is None:
102 | raise SyntaxError('Invalid define specification')
103 | m = match.groupdict()
104 | define_key = m['key'].strip()
105 | define_val = m['val'].strip()
106 | if (define_key == '' or define_val == ''):
107 | print(line)
108 | raise SyntaxError('Invalid define specification')
109 | define_directives[define_key] = define_val
110 | current_field = None
111 | for line in text.splitlines():
112 | self.linenum = self.linenum + 1
113 | print("%s %s" % (self.linenum, line))
114 | if (line.startswith('#define')):
115 | parse_define_directive(line)
116 | continue
117 | if line.strip()=='':
118 | continue
119 | match = self.line_template.match(line)
120 | if match is None:
121 | line = line.strip()
122 | if line == '---':
123 | error = process_expression(expression)
124 | if error is not None:
125 | raise SyntaxError(error)
126 | expression = {}
127 | continue
128 | if current_field is not None:
129 | if current_field == 'Macro':
130 | if len(self.macro) == 0:
131 | self.macro.append(expression['Macro'])
132 | param_match = self.param_template.match(line)
133 | if param_match is None:
134 | raise SyntaxError('Unexpected macro param format: "%s" for macro "%s"' % (line,self.macro[1]))
135 | else:
136 | self.macro.append(param_match.groupdict()['val'].strip())
137 | continue
138 | else:
139 | expression[current_field] += ' ' + line
140 | continue
141 | raise SyntaxError('Unexpected format')
142 | m = match.groupdict()
143 | m['key'] = m['key'].strip()
144 | m['val'] = m['val'].strip()
145 | current_field = m['key']
146 | if m['key'] == 'SET' or m['key'] == 'LET':
147 | expression['name'] = m['val']
148 | expression['command'] = m['key']
149 | elif m['key'] in self.ALLOWED_TAGS:
150 | expression[m['key']] = m['val']
151 | else:
152 | if m['key'] == 'Macro':
153 | self.macro.append(m['val'])
154 | expression['Macro'] = self.macro
155 | else:
156 | raise SyntaxError('Unexpected QlikView expression property: "%s"' % m['key'])
157 | error = process_expression(expression)
158 | if error is not None:
159 | raise SyntaxError(error)
160 | return None
161 | class QlikViewCommandExpander:
162 | expressions = []
163 | exp_dict = {}
164 | output = []
165 | VAR_PATTERN = re.compile('\\$\\((?P[^=][^)]+)\\)')
166 | def __init__(self, expressions, expressionsToExpand = None):
167 | self.expressions = list(expressions)
168 | if expressionsToExpand is not None:
169 | self.expressionsToExpand = list(expressionsToExpand)
170 | for exp in self.expressions:
171 | if '.' in exp[0]:
172 | continue
173 | self.exp_dict[exp[0]] = exp[1]
174 | def expand(self):
175 | for exp in self.expressions:
176 | expanded = exp[1]
177 | for match in self.VAR_PATTERN.finditer(exp[1]):
178 | variable = match.groupdict()['key']
179 | if variable in self.exp_dict:
180 | replace_string = self.exp_dict[variable]
181 | expanded = expanded.replace('$(%s)' % variable, replace_string)
182 | else:
183 | print('Cannot find variable: %s for expression %s' % (variable,exp[0]))
184 | self.output.append((exp[0],expanded))
185 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | InQlik Tools for Sublime Text
2 | =============================
3 |
4 | ##Language plugin for QlikView load scripts
5 |
6 |
7 | ###Syntax Highlighting
8 |
9 | * Both block comments (/\* \*/) and line comments (//) are supported. CTRL-/ key combination comment/uncomment code block with line comments (//)
10 | * Variables, built-in functions and so on are trying properly show their boundaries by by coloring corresponding braces.
11 | * Nesting supported for all constructs - variable as parameter of function, function within function, function within variable and so on
12 | * Conflicts between some build-in functions and keywords (IF, LEFT, RIGHT, REPLACE) are resolving by context
13 |
14 | 
15 |
16 | ####Symbols
17 |
18 | In qvs files subroutine names, variables in variable assignment commands and table identifiers marked as symbols. So `Goto Definition`, `Goto Symbol` and `Goto Symbol in Project` commands work.
19 |
20 | ####Goto file
21 |
22 | You can open any file in your project's directories from within qvs script. Default keymap is `Ctrl-F12`. That is something like [Open-include](https://github.com/SublimeText/Open-Include) but it can properly open files when part of the path presented by qlikview variables (important in Qlikview Deployment Framework environment). It is useful for opening of include scripts, qvd files (in embedded metadata viewer),
23 | and so on.
24 |
25 | ####Build System
26 |
27 | Build system allow to `batch reload` of qvw file from within of corresponding qvs script file opened in Sublime Text.
28 | To run `batch reload` Sublime Text should be able to find corresponding qvw file.
29 | By default it will look up qvw file with same name as qvs script in same directory. For example: We are editing file `c:\QvProjects\Project1\Apps\LoadData.qvs` in Sublime Text. By invoking build system (keyboard shortcuts for this command are `F7` or `Ctrl-B`) we effectively run shell command
30 |
31 | c:\Program Files\QlikView\qv.exe /R /NoData c:\QvProjects\Project1\Apps\LoadData.qvw
32 |
33 | Load script in your LoadData.qvw file should contain include directive pointing to LoadData.qvs, for example `$(must_include=LoadData.qvs)`
34 |
35 | If qvw file stays in another directory it may be indicated explicitly in first line of qvs script file by shebang-like comment string. For example, if your script file is `c:\QvProjects\Project1\Scripts\LoadData.qvs` corresponding qvd-generator `c:\QvProjects\Project1\Apps\LoadData.qvw` would be found if qvs script has first line
36 |
37 | //#!c:\QvProjects\Project1\Apps\LoadData.qvw
38 |
39 | You may also use relative path syntax and skip file part of path string if base names of qvs and qvw file are identical. So in our last example we with same effect may put in first line of qvs script
40 |
41 | //#!..\Apps
42 |
43 | `Ctrl-Shift-B` key combination opens corresponding qlikview application instead of reloading it
44 |
45 | ####QVD Viewer
46 |
47 | Clicking on QVD file in project panel instantly open view with information available in qvd header and LOAD statement for that QVD
48 |
49 | 
50 |
51 | ####QVW.LOG file viewer
52 |
53 | While you editing qvs script file `Ctrl-Shift-L` key combination or menu command `Tools->Packages->InQlik-Tools->Open and refomat qvw.log file` opens qvw.log file corresponding to currently edited script. If you open qvw.log file directly `Ctrl-Shift-L` key combination or menu command just reformat log file.
54 |
55 | 
56 |
57 | - Output of qlikview script, including output from TRACE command are formatted as comment
58 | - Input commands are cleared from timestamp info
59 | - Syntax coloring is applied to input commands
60 | - Tables, variables and subroutine definitions are not added to list of defined symbols (Goto definition for example never jump to qvw.log file but to source qvs file)
61 |
62 | ##Expression Editor: Language plugin for editing QlikView expressions and variables
63 |
64 | *Article about Expression Editor with downloadable sample project placed [here](http://community.qlik.com/docs/DOC-6033) and [here](http://inqlik.github.io/2014/02/expression-editor/)*
65 |
66 | Expression editor used to write and store QlikView variables in convenient form.
67 | Expression editor use YAML like format.
68 |
69 | ####Syntax highlighting
70 |
71 | Expression editor highlight both syntax for it format and syntax of QlikView expressions edited.
72 |
73 | 
74 |
75 | #####Formats of autogenerated file
76 |
77 | On every save plugin autogenerate external file in one of available formats:
78 |
79 | - Csv variable file in format used by QlikView Deployment Framework (by `LoadVariableCSV` subroutine). That is default option `QDF`.
80 | - Csv file in table format (option `CSV`), each row corresponds to whole expression and contains fields
81 | - Name
82 | - Definition
83 | - Label
84 | - Comment
85 | - Descirption
86 | - Section
87 |
88 | Current export format can be changed at menu item `Preferences->Packages Settings->InQlik-Tools->QlikView variables file settings: User`
89 | #####Mandatory tags:
90 |
91 | - LET or SET: precede name of expression. Corresponds to `Variable` field of standard QDF variable csv file
92 | - Definition: Corresponds to `VariableValue` field.
93 |
94 | #####Optional tags:
95 |
96 | - Tag (exported as `Priority` field of csv variable file)
97 | - Description (exported as `Comments` field of csv variable file)
98 |
99 | #####Optional tags exported as additional variables in `QDF` format (additional rows in csv variable file)
100 |
101 | - label
102 | - comment
103 | - backgroundColor
104 | - fontColor
105 | - nextFormat
106 | - enableCondition
107 | - showCondition
108 | - sortBy
109 | - visualCueUpper
110 | - visualCueLower
111 | - symbol
112 | - thousandSymbol
113 | - villionSymbol
114 | - billionSymbol
115 |
116 | Usual minimal expression definition looks like
117 |
118 | ```
119 | ---
120 | set: SalesSum
121 | definition: Sum({} Amount)
122 | label: Sales
123 | comment: Sales amount
124 | ```
125 | And corresponding auto-generated csv file would be
126 |
127 | ```
128 | VariableName,VariableValue,Comments,Priority
129 | SET SalesSum,Sum({} Amount),,
130 | SET SalesSum.Comment,Sales amount,,
131 | SET SalesSum.Label,Sales,,
132 | ```
133 |
134 | ####Symbols
135 |
136 | In qlikview-vars files expression names (name after `LET` or `SET` tag) marked as symbols. So `Goto Definition`, `Goto Symbol` and `Goto Symbol in Project` commands work for expressions.
137 |
138 | ####Syntax checks
139 |
140 | Minimal syntax checks provided: Checks for mandatory tags, checks for uniqueness of expression names
141 |
142 | ####Expand variables mode
143 |
144 | Given expressions
145 |
146 | ```
147 | ---
148 | set: SalesSum
149 | definition: Sum({} Amount)
150 | label: Sales
151 | comment: Sales amount
152 | ---
153 | set: CostSum
154 | definition: Sum({} Amount)
155 | label: Cost
156 | comment: Cost amount
157 | ---
158 | set: MarginAmout
159 | definition: ($(SalesSum) - $(CostSum))
160 | label: Margin
161 | comment: Margin amount
162 | ```
163 | Expression `MarginAmount` defined in terms of expressions `SalesSum` and `CostSum`. Normally `MarginAmount` would be exported in same form to csv file. So in `QDF` format it would be
164 |
165 | ```
166 | SET MarginAmout,($(SalesSum) - $(CostSum)),,
167 | ```
168 | You can expand variables before export expressions (Menu command `Tools\Packages\InQlik-Tools\Expand variables and export file` or `Ctrl-Shift-S` key combination). So target expression in export file would be
169 |
170 | ```
171 | SET MarginAmout,(Sum({} Amount) - Sum({} Amount)),,
172 | ```
173 |
174 |
175 | ## Installation :
176 |
177 | ### Using [Package Control][1] (*Recommended*)
178 |
179 | For all Sublime Text 2/3 users we recommend install via [Package Control][1].
180 |
181 | 1. [Install][2] Package Control if you haven't yet.
182 | 2. Use `Ctrl+Shift+P` then `Package Control: Install Package`
183 | 3. Look for `InQlik-Tools` and install it.
184 |
185 | ### Manual Install
186 |
187 | 1. Click the `Preferences > Browse Packages…` menu
188 | 2. Download [zip package][3] and extract its content into `InQlik-Tools` directory in this folder. (Check that README.md is immediately under `InQlik-Tools' folder not in nested folder)
189 | 3. Restart Sublime Text
190 |
191 | [Last changes](CHANGELOG.md)
192 |
193 | ### Compatibility
194 |
195 | I've switched to ST3, further development will be focused on that platform.
196 | Basic functionality (syntax highlighting for qvs files and expression files) should work on ST2.
197 | Specifically QVD viewer does not work for ST2 and disabled explicitly in it.
198 |
199 |
200 |
201 | [home]: https://github.com/inqlik/inqlik-tools
202 | [1]: https://sublime.wbond.net/
203 | [2]: https://sublime.wbond.net/installation
204 | [3]: https://github.com/inqlik/inqlik-tools/archive/master.zip
205 |
--------------------------------------------------------------------------------
/Syntax/QlikView script.YAML-tmLanguage:
--------------------------------------------------------------------------------
1 | # [PackageDev] target_format: plist, ext: tmLanguage
2 | name: QlikView script file
3 | scopeName: source.qvs
4 | fileTypes: [qvs]
5 | uuid: 6b77dc03-7003-41f4-a9f6-287849f88d4f
6 |
7 | patterns:
8 | - include: '#subroutine'
9 |
10 | - include: '#null_assignment'
11 |
12 | - include: '#assignment'
13 |
14 | - include: '#tab'
15 |
16 | - include: '#comments'
17 |
18 | - include: '#strings'
19 |
20 | - include: '#numericLiterals'
21 |
22 | - include: '#variables'
23 |
24 | - include: '#qualifiers'
25 |
26 | - include: '#functions'
27 |
28 | - include: '#keyword'
29 |
30 | - include: '#operators'
31 |
32 | - include: '#tableIdentifiers'
33 |
34 | - include: '#braces'
35 |
36 |
37 | repository:
38 | braces:
39 | patterns:
40 | - begin: \(
41 | beginCaptures:
42 | '0': {name: support.constant.qvs}
43 | end: \)
44 | endCaptures:
45 | '0': {name: support.constant.qvs}
46 | patterns:
47 | - include: '#fileQualifiers'
48 | - include: '#functions'
49 | - include: '#variables'
50 | - include: '#braces'
51 | - include: '#strings'
52 | - include: '#numericLiterals'
53 |
54 | comments:
55 | patterns:
56 | - name: comment.line.double-dash.source.qvs
57 | begin: //
58 | end: $\n
59 | - name: comment.line.rem.source.qvs
60 | begin: '^\s*REM '
61 | end: $\n
62 | - name: comment.block.source.qvs
63 | begin: /\*
64 | end: \*/
65 |
66 | fileQualifiers:
67 | patterns:
68 | - name: support.constant.qvs
69 | match: (?i)(?<=\s|\(|,)(codepage is \d+|ansi|oem|mac|utf8|unicode|qvd|qvx|txt|fix|dif|biff|html|delimiter
70 | is|no eof|no quotes|msq|xmlsax|xmlsimple|no labels|embedded labels|explicit
71 | labels|no eof|msq|header is (\d+ lines)?|record is (\d+ lines)?)|table is
72 |
73 | functions:
74 | patterns:
75 | - begin: (?i)(\b|=)(if|getselectedcount|aggr|left|right|acos|addmonths|addyears|age|alt|applycodepage|applymap|argb|asin|atan|atan2|attribute|author|autonumber|autonumberhash128|autonumberhash256|avg|bitcount|black|blackandschole|blue|brown|capitalize|ceil|chi2test_chi2|chi2test_df|chi2test_p|chidist|chiinv|chr|class|clientplatform|color|colormaphue|colormapjet|colormix1|colormix2|combin|computername|concat|connectstring|converttolocaltime|correl|cos|cosh|count|cyan|darkgray|date|date#|day|dayend|daylightsaving|dayname|daynumberofquarter|daynumberofyear|daystart|div|DocumentName|DocumentPath|DocumentTitle|Dual|e|Evaluate|Even|Exists|exp|fabs|Fact|False|FDIST|FieldIndex|FieldName|FieldNumber|FieldValue|FieldValueCount|FileBaseName|FileDir|FileExtension|FileName|FilePath|FileSize|FileTime|FindOneOf|FINV|FirstSortedValue|FirstValue|FirstWorkDate|Floor|fmod|Frac|Fractile|FV|GetExtendedProperty|GetFolderPath|GetObjectField|GetRegistryString|GMT|Green|Hash128|Hash160|Hash256|Hour|HSL|InDay|InDayToTime|Index|InLunarWeek|InLunarWeekToDate|InMonth|InMonths|InMonthsToDate|InMonthToDate|Input|InputAvg|InputSum|InQuarter|InQuarterToDate|Interval|Interval#|InWeek|InWeekToDate|InYear|InYearToDate|IRR|IsNull|IsNum|IsPartialReload|IsText|IterNo|KeepChar|Kurtosis|LastValue|LastWorkDate|Len|LightBlue|LightCyan|LightGray|LightGreen|LightMagenta|LightRed|LINEST_B|LINEST_DF|LINEST_F|LINEST_M|LINEST_R2|LINEST_SEB|LINEST_SEM|LINEST_SEY|LINEST_SSREG|LINEST_SSRESID|LocalTime|log|log10|Lookup|Lower|LTrim|LunarWeekEnd|LunarWeekName|LunarWeekStart|Magenta|MakeDate|MakeTime|MakeWeekDate|MapSubString|Match|Max|MaxString|Median|Mid|Min|MinString|Minute|MissingCount|MixMatch|Mod|Mode|Money|Money#|Month|MonthEnd|MonthName|MonthsEnd|MonthsName|MonthsStart|MonthStart|MsgBox|NetWorkDays|NoOfFields|NoOfReports|NoOfRows|NoOfTables|NORMDIST|NORMINV|Now|nPer|NPV|Null|NullCount|Num|Num#|NumAvg|NumCount|NumericCount|NumMax|NumMin|NumSum|Odd|Only|Ord|OSUser|Peek|Permut|Pi|Pick|Pmt|pow|Previous|PurgeChar|PV|QlikTechBlue|QlikTechGray|QlikViewVersion|QuarterEnd|QuarterName|QuarterStart|QvdCreateTime|QvdFieldName|QvdNoOfFields|QvdNoOfRecords|QvdTableName|QVUser|Rand|RangeAvg|RangeCorrel|RangeCount|RangeFractile|RangeIRR|RangeKurtosis|RangeMax|RangeMaxString|RangeMin|RangeMinString|RangeMissingCount|RangeMode|RangeNPV|RangeNullCount|RangeNumericCount|RangeOnly|RangeSkew|RangeStdev|RangeSum|RangeTextCount|RangeXIRR|RangeXNPV|Rank|Rate|RecNo|Red|ReloadTime|Repeat|Replace|ReportComment|ReportId|ReportName|ReportNumber|RGB|Round|RowNo|RTrim|Second|SetDateYear|SetDateYearMonth|Sign|sin|sinh|Skew|sqr|sqrt|Stdev|Sterr|STEYX|SubField|SubStringCount|Sum|SysColor|TableName|TableNumber|tan|tanh|TDIST|Text|TextBetween|TextCount|Time|Time#|Timestamp|Timestamp#|TimeZone|TINV|Today|Trim|True|TTest1_conf|TTest1_df|TTest1_dif|TTest1_lower|TTest1_sig|TTest1_sterr|TTest1_t|TTest1_upper|TTest1w_conf|TTest1w_df|TTest1w_dif|TTest1w_lower|TTest1w_sig|TTest1w_sterr|TTest1w_t|TTest1w_upper|TTest_conf|TTest_df|TTest_dif|TTest_lower|TTest_sig|TTest_sterr|TTest_t|TTest_upper|TTestw_conf|TTestw_df|TTestw_dif|TTestw_lower|TTestw_sig|TTestw_sterr|TTestw_t|TTestw_upper|Upper|UTC|Week|WeekDay|WeekEnd|WeekName|WeekStart|WeekYear|White|WildMatch|WildMatch5|XIRR|XNPV|Year|Year2Date|YearEnd|YearName|YearStart|YearToDate|Yellow|ZTest_conf|ZTest_dif|ZTest_lower|ZTest_sig|ZTest_sterr|ZTest_upper|ZTest_z|ZTestw_conf|ZTestw_dif|ZTestw_lower|ZTestw_sig|ZTestw_sterr|ZTestw_upper|ZTestw_z)(\s*\()
76 | beginCaptures:
77 | '2': {name: entity.other.attribute-name.qvs}
78 | '3': {name: entity.other.attribute-name.qvs}
79 | end: \)
80 | endCaptures:
81 | '0': {name: entity.other.attribute-name.qvs}
82 | patterns:
83 | - include: '#comments'
84 | - include: '#variables'
85 | - include: '#functions'
86 | - include: '#qualifiers'
87 | - include: '#numericLiterals'
88 | - include: '#operators'
89 | - include: '#strings'
90 | - include: '#braces'
91 |
92 | keyword:
93 | patterns:
94 | - match: (?i)(^|\s)\b(SUB|NOT|OR|AND|ADD|ALIAS|ASC|BINARY|BUFFER|BUNDLE|CALL|COMMENT|CONCATENATE|CONNECT|CROSSTABLE|DESC|DIRECTORY|DISCONNECT|DO|DROP|EXECUTE|EACH|END|EXIT|FIELD|FIELDS|FIRST|FOR|FORCE|GENERIC|HIERARCHY|HIERARCHYBELONGSTO|THEN|ELSEIF|ELSE|ENDIF|IMAGE_SIZE|INFO|INNER|INPUTFIELD|INTERVALMATCH|JOIN|KEEP|LOAD|LOOSEN|MAPPING|MAP|USING|NOCONCATENATE|NULLASVALUE|NULLASNULL|OUTER|QUALIFY|RENAME|RIGHT|SAMPLE|SECTION|SELECT|SEMANTIC|SEMANTIC|SLEEP|SQL|SQLCOLUMNS|SQLTABLES|SQLTYPES|STAR|STORE|ENDSUB|SWITCH|CASE|DEFAULT|ENDSWITCH|TAG|TRACE|UNLESS|UNMAP|UNQUALIFY|UNTAG|WHEN|LOOP|NEXT|SCRIPT|TABLE|TABLES|FROM|INTO|AS|INTO|TO|STEP|AUTOGENERATE|RESIDENT|WHILE|WHERE|ORDER|GROUP|BY|WITH)\b
95 | captures:
96 | '2': {name: keyword.control.qvs}
97 | - match: (?i)(^|\s)(LEFT|RIGHT|IF|REPLACE)(?!\()
98 | captures:
99 | '2': {name: keyword.control.qvs}
100 |
101 | numericLiterals:
102 | patterns:
103 | - match: (?<=\s|^|=|\(|,|>|<|\+|/|\*)(\-?\d+)(\.\d+)?
104 | captures:
105 | '1': {name: constant.numeric.qvs}
106 | '2': {name: constant.numeric.qvs}
107 |
108 | subroutine:
109 | patterns:
110 | - match: ^\s*([Ss][Uu][Bb])\s+((?:\w|\.)+)
111 | captures:
112 | '1': {name: keyword.control.qvs}
113 | '2': {name: support.class entity.name.type.subroutine.qvs}
114 |
115 | null_assignment:
116 | patterns:
117 | - match: ^\s*([LlSs][Ee][Tt])\s+(\w|\.)+\s*=\s*;
118 | captures:
119 | '1': {name: keyword.control.qvs}
120 | assignment:
121 | patterns:
122 | - match: ^\s*([LlSs][Ee][Tt])\s+((\w|\.)+)\s*=
123 | captures:
124 | '1': {name: keyword.control.qvs}
125 | '2': {name: entity.name.type.variable.qvs}
126 |
127 | tab:
128 | patterns:
129 | - match: ^(///\$tab) (.+)$
130 | captures:
131 | '1': {name: comment.line.double-dash.source.qvs}
132 | '2': {name: support.constant.qvs meta.tab.qvs}
133 | operators:
134 | patterns:
135 | - name: keyword.control.qvs
136 | match: (&|/)
137 | - name: keyword.control.qvs
138 | match: (?i)\b(AND|OR)\b
139 |
140 | qualifiers:
141 | patterns:
142 | - match: (?i)(DISTINCT|TOTAL)(\s|<)
143 | captures:
144 | '1': {name: keyword.control.qvs}
145 |
146 | strings:
147 | patterns:
148 | - name: string.double.quoted.qvs
149 | begin: '"'
150 | end: '"'
151 | patterns:
152 | - include: '#variables'
153 | - name: string.single.quoted.qvs
154 | begin: "'"
155 | end: "'"
156 | patterns:
157 | - include: '#variables'
158 | - name: string.single.quoted.qvs
159 | begin: \[
160 | end: \]
161 | patterns:
162 | - include: '#variables'
163 |
164 | tableIdentifiers:
165 | patterns:
166 | - name: support.constant.qvs
167 | match: ^(\s)*(\w+):(\s)*$
168 | captures:
169 | '2': {name: support.constant.qvs entity.name.type.table.qvs}
170 | variables:
171 | patterns:
172 | - name: variable.parameter.qvs
173 | begin: \$\(
174 | beginCaptures:
175 | '0': {name: variable.parameter.qvs}
176 | end: \)
177 | endCaptures:
178 | '0': {name: variable.parameter.qvs}
179 | patterns:
180 | - include: '#functions'
181 | - include: '#variables'
182 | - include: '#numericLiterals'
183 | - include: '#braces'
184 | - name: variable.parameter.qvs
185 | match: \$\d+
186 |
--------------------------------------------------------------------------------
/qlickview_vars.py:
--------------------------------------------------------------------------------
1 | import sublime
2 | import sublime_plugin
3 | import os
4 | import re
5 | import xml.etree.ElementTree as etree
6 | import csv
7 | import sys
8 | import datetime
9 | from sublime import Region
10 | from .util.qvvars import QlikViewCommandExpander
11 | import json
12 | #from .util.qvvars import QvVarFileReader
13 |
14 |
15 | EXT_QLIKVIEW_VARS = ".qlikview-vars"
16 | class QlikviewVariableFileListener(sublime_plugin.EventListener):
17 | """Save variables in one of export formats
18 | along with current expression file in YAML like format (extentsion EXT_QLIKVIEW_VARS)
19 |
20 | Implements:
21 | on_post_save"""
22 | EXT_QLIKVIEW_VARS = ".qlikview-vars"
23 | EXT_QLIKVIEW_QDF_CSV = ".csv"
24 | EXT_QLIKVIEW_TABLE_CSV = ".table.csv"
25 | EXT_QLIKVIEW_VARS_QVS = ".vars.qvs"
26 | EXT_QLIKVIEW_VARS_JSON = ".json"
27 | modulesettings = None
28 | reader = None
29 | def is_ST3(self):
30 | ''' check if ST3 based on python version '''
31 | version = sys.version_info
32 | if isinstance(version, tuple):
33 | version = version[0]
34 | elif getattr(version, 'major', None):
35 | version = version.major
36 | return (version >= 3)
37 | def on_post_save(self, view):
38 | fn = view.file_name()
39 | if (fn.endswith(self.EXT_QLIKVIEW_VARS)):
40 | view.window().run_command("qlikview_variables_export")
41 |
42 | class QlikviewVariablesExportCommand(sublime_plugin.WindowCommand):
43 | """Save variables in one of export formats
44 | along with current expression file in YAML like format (extentsion EXT_QLIKVIEW_VARS)
45 |
46 | Implements:
47 | on_post_save"""
48 | EXT_QLIKVIEW_VARS = ".qlikview-vars"
49 | EXT_QLIKVIEW_QDF_CSV = ".csv"
50 | EXT_QLIKVIEW_TABLE_CSV = ".table.csv"
51 | EXT_QLIKVIEW_VARS_QVS = ".vars.qvs"
52 | EXT_QLIKVIEW_VARS_JSON = ".json"
53 | modulesettings = None
54 | reader = None
55 | def is_ST3(self):
56 | ''' check if ST3 based on python version '''
57 | version = sys.version_info
58 | if isinstance(version, tuple):
59 | version = version[0]
60 | elif getattr(version, 'major', None):
61 | version = version.major
62 | return (version >= 3)
63 | def run(self, commandVariant=None):
64 | view = self.window.active_view()
65 | fn = view.file_name()
66 | if (fn.endswith(self.EXT_QLIKVIEW_VARS)):
67 | self.modulesettings = view.settings()
68 | self.reader = QvVarFileReader(self.modulesettings)
69 | self.regenerate_expression_tab_file(view.file_name())
70 |
71 | def regenerate_tab_file_content(self,path, onload=False):
72 | (name, ext) = os.path.splitext(os.path.basename(path))
73 | f = None
74 | if self.is_ST3():
75 | f = open(path, 'r', encoding="utf-8")
76 | else:
77 | f = open(path, 'rb')
78 | read = f.read()
79 | f.close()
80 |
81 | try:
82 | self.reader.parse_content(read)
83 | except Exception as e:
84 | msg = isinstance(e, SyntaxError) and str(e) or "Error parsing QlikView expression "
85 | msg += " in file `%s` line: %d" % (path, self.reader.linenum)
86 | if onload:
87 | # Sublime Text likes "hanging" itself when an error_message is pushed at initialization
88 | print("Error: " + msg)
89 | else:
90 | sublime.error_message(msg)
91 | if not isinstance(e, SyntaxError):
92 | print(e) # print the error only if it's not raised intentionally
93 | return None
94 | def regenerate_expression_tab_file(self,path, onload=False, force=False):
95 | start = datetime.datetime.utcnow()
96 | output_mode = self.modulesettings.get("output_mode","QDF")
97 | expandVariables = self.modulesettings.get("expand_variables",False);
98 | print("expandVariables: %s" % expandVariables)
99 | if output_mode == 'QDF':
100 | outExt = self.EXT_QLIKVIEW_QDF_CSV
101 | elif output_mode == 'QVS':
102 | outExt = self.EXT_QLIKVIEW_VARS_QVS
103 | elif output_mode == 'JSON':
104 | outExt = self.EXT_QLIKVIEW_VARS_JSON
105 | elif output_mode == 'CSV':
106 | outExt = self.EXT_QLIKVIEW_TABLE_CSV
107 | else:
108 | sublime.error_message('Unknown output_format %s. Known formats are QDF (Csv file QlikView Deployment framework), QVS (Plain include script), CSV (Plain tabular csv)')
109 | outPath = path.replace(self.EXT_QLIKVIEW_VARS,outExt)
110 | self.regenerate_tab_file_content(path, onload=onload)
111 | f = None
112 | if self.is_ST3():
113 | if output_mode == 'QDF':
114 | enc = 'utf-8'
115 | elif output_mode == 'CSV':
116 | enc = 'utf-8-sig'
117 | else:
118 | enc = 'utf-8-sig'
119 | f = open(outPath, 'w', encoding=enc, newline='')
120 | else:
121 | f = open(outPath,'wb')
122 | if expandVariables == True:
123 | print('Expandind variables')
124 | expander = QlikViewVariableExpander(self.reader.output)
125 | expander.expandAll()
126 | for exp in self.reader.expressions:
127 | exp['expandedDefinition'] = expander.exp_dict[exp.get('name')]
128 | if output_mode == 'QDF':
129 | writer = csv.writer(f)
130 | writer.writerow(['VariableName','VariableValue','Comments','Priority'])
131 | for row in self.reader.output:
132 | writer.writerow(['%s %s' % (row[0] , row[1]), expander.exp_dict[row[1]] if expandVariables else row[2], row[3], row[4]])
133 | elif output_mode == 'QVS':
134 | f.write('//////THIS IS AUTOGENERATED FILE. DO NOT EDIT IT DIRECTLY!!!!!!!!!!!!!\n\n')
135 | for row in self.reader.output:
136 | exp = expander.exp_dict[row[1]] if expandVariables else row[2]
137 | if '$(' in exp:
138 | command = 'let'
139 | exp = exp.replace("'","~~~")
140 | exp = exp.replace("$(","@(")
141 | exp = "replace(replace('%s','~~~', chr(39)), '@(', chr(36) & '(')" % exp
142 | else:
143 | command = row[0]
144 | varName = row[1]
145 | line = "%s %s = %s;\n" % (command,varName,exp)
146 | f.write(line)
147 | elif output_mode == 'JSON':
148 | jsonContent = json.dumps(self.reader.expressions, sort_keys=True, indent=4, ensure_ascii=False)
149 | f.write(jsonContent)
150 | elif output_mode == 'CSV':
151 | writer = csv.writer(f)
152 | writer.writerow(['ExpressionName','Label','Comment','Description','Section','Definition','Width'])
153 | for exp in self.reader.expressions:
154 | writer.writerow([exp.get('name'),exp.get('label'),exp.get('comment'),exp.get('description'),None,exp.get('expandedDefinition') if expandVariables else exp.get('definition'),exp.get('width')])
155 | f.close()
156 | print(' Saving elapsed: ' + str(datetime.datetime.utcnow()-start))
157 |
158 |
159 | class QvVarFileReader:
160 | ALLOWED_TAGS = ('label','comment', 'definition','backgroundColor','fontColor','textFormat',
161 | 'tag','separator','#define', 'macro','description','enableCondition',
162 | 'showCondition','sortBy','visualCueUpper','visualCueLower','width','symbol',
163 | 'thousandSymbol','millionSymbol','billionSymbol','family','type', 'selectorLabel', 'format', 'calendar')
164 | FIELDS_TO_SKIP = ('definition','tag','set','let','command','name','separator','macro','description', 'family', 'type', 'selectorLabel', 'format')
165 | NAME_MAP = {}
166 |
167 | line_template = re.compile(r'^(?P\w+?):\s*(?P.*)$')
168 | define_template = re.compile(r'^#define\s*(?P\S+)\s+(?P.*)$')
169 | param_template = re.compile(r'^\s*\-\s*(?P.*)$')
170 |
171 | linenum = 0
172 | defs = {}
173 | macro = []
174 | output = []
175 | expressions = []
176 | define_directives = {}
177 | modulesettings = None
178 | def __init__(self,modulesettings):
179 | self.linenum = 0
180 | self.defs = {}
181 | self.macro = []
182 | self.output = []
183 | self.define_directives = {}
184 | self.modulesettings = modulesettings
185 | self.currentSection = ''
186 | def put_row(self, key, value, command, comment, priority):
187 | self.output.append([command.upper(), key ,value, comment, priority])
188 | def parse_content(self,text):
189 | self.NAME_MAP = {}
190 | mappings = self.modulesettings.get('mappings',{})
191 | for tag in self.ALLOWED_TAGS:
192 | self.NAME_MAP[tag] = mappings.get(tag,tag)
193 | self.NAME_MAP['separator'] = self.modulesettings.get('separator','.')
194 | expression = {}
195 | defs = {}
196 | surrogateNames = {}
197 | define_directives = {}
198 | self.linenum = 0
199 | self.macro = []
200 | self.output = []
201 | self.expressions = []
202 | def expand_macro():
203 | if defs.get(self.macro[0]) is None:
204 | raise SyntaxError('Parsing error: definition for macro `%s` is not found' % self.macro[0])
205 | result = defs[self.macro[0]]
206 | i = 1
207 | while i < len(self.macro):
208 | param = self.macro[i]
209 | subs = '$%s' % str(i)
210 | if not subs in result:
211 | print('macro',self.macro)
212 | raise SyntaxError('Parsing error: definition for macro `%s` does not contain substring %s' % (self.macro[0],subs))
213 | result = result.replace(subs,param)
214 | i = i + 1
215 | return result
216 | def init_expression():
217 | self.macro = []
218 | expression = {}
219 | def process_expression(exp):
220 | if exp == {}:
221 | return None
222 | expFamily = exp.get('family')
223 | expType = exp.get('type')
224 | expCalendar = exp.get('calendar')
225 | surrogateName = ''
226 | if ((expFamily is not None) and (expType is not None)):
227 | surrogateName = expFamily + '|' + expType
228 | if (expCalendar is not None):
229 | surrogateName = surrogateName + '|' + expCalendar
230 | name = exp.get('name')
231 | if (name is None):
232 | if (surrogateName == ''):
233 | return 'Parsing error: `name` property (or family, type, calendar) is absent'
234 | else:
235 | name = surrogateName
236 | exp['name'] = name
237 | if name in defs:
238 | return 'Parsing error: duplicate expression with name `%s`' % name
239 | if surrogateName in surrogateNames:
240 | return 'Parsing error: duplicate expression with surrogate name `%s`' % surrogateName
241 | if exp.get('definition') is not None and exp.get('macro') is not None:
242 | return 'Parsing error: Expression have defined both `definition` and `macro` property. Something one must be defined'
243 | if exp.get('definition') is None:
244 | if exp.get('macro') is None:
245 | return 'Parsing error: Expression `%s` have not defined `definition` or `macro` property' % exp['name']
246 | exp['definition'] = expand_macro()
247 | local_def = exp['definition']
248 | for k, v in define_directives.items():
249 | local_def = local_def.replace(k,v)
250 | exp['definition'] = local_def
251 | defs[name] = exp['definition']
252 | if (surrogateName != ''):
253 | surrogateNames[surrogateName] = 0
254 | comment = exp.get('Description')
255 | tag = exp.get('tag')
256 | if tag is None:
257 | tag = self.currentSection
258 | command = exp.get('command')
259 | if (command is None):
260 | command = name
261 | self.expressions.append(exp)
262 | self.put_row(name,expression['definition'],command, comment, tag)
263 | for key in exp.keys():
264 | if key not in self.FIELDS_TO_SKIP:
265 | varName = '%s%s%s' % (name,self.NAME_MAP['separator'],self.NAME_MAP[key])
266 | self.put_row(varName,expression[key],'set', '', tag)
267 | init_expression()
268 | return None
269 | def parse_val(text):
270 | if text == None:
271 | return ''
272 | return text.strip()
273 | def parse_define_directive(line):
274 | match = self.define_template.match(line)
275 | if match is None:
276 | raise SyntaxError('Invalid define specification')
277 | m = match.groupdict()
278 | define_key = m['key'].strip()
279 | define_val = m['val'].strip()
280 | if (define_key == '' or define_val == ''):
281 | print(line)
282 | raise SyntaxError('Invalid define specification')
283 | define_directives[define_key] = define_val
284 | current_field = None
285 | for line in text.splitlines():
286 | self.linenum = self.linenum + 1
287 | #print("%s %s" % (self.linenum, line))
288 | if (line.startswith('#define')):
289 | parse_define_directive(line)
290 | continue
291 | if line.strip()=='':
292 | continue
293 | if (line.startswith('#SECTION ')):
294 | self.currentSection = re.sub("#SECTION :?", "", line)
295 | continue
296 | match = self.line_template.match(line)
297 | if match is None:
298 | line = line.strip()
299 | if line == '---':
300 | error = process_expression(expression)
301 | if error is not None:
302 | raise SyntaxError(error)
303 | expression = {}
304 | continue
305 | if current_field is not None:
306 | if current_field == 'macro':
307 | if len(self.macro) == 0:
308 | self.macro.append(expression['macro'])
309 | param_match = self.param_template.match(line)
310 | if param_match is None:
311 | raise SyntaxError('Unexpected macro param format: "%s" for macro "%s"' % (line,self.macro[1]))
312 | else:
313 | self.macro.append(param_match.groupdict()['val'].strip())
314 | continue
315 | else:
316 | expression[current_field] += ' ' + line
317 | continue
318 | raise SyntaxError('Unexpected format')
319 | m = match.groupdict()
320 | m['key'] = m['key'].strip()
321 | m['val'] = m['val'].strip()
322 | current_field = m['key']
323 | if m['key'] == 'set' or m['key'] == 'let':
324 | expression['name'] = m['val']
325 | expression['command'] = m['key']
326 | elif m['key'] in self.ALLOWED_TAGS:
327 | expression[m['key']] = m['val']
328 | else:
329 | if m['key'] == 'macro':
330 | self.macro.append(m['val'])
331 | expression['macro'] = self.macro
332 | else:
333 | raise SyntaxError('Unexpected QlikView expression property: "%s"' % m['key'])
334 | error = process_expression(expression)
335 | if error is not None:
336 | raise SyntaxError(error)
337 | return None
338 | class QlikViewVariableExpander:
339 | expressions = []
340 | exp_dict = {}
341 | output = []
342 | not_found = set()
343 | VAR_PATTERN = re.compile('\\$\\((?P[^=$][^())]+)\\)')
344 | def __init__(self, expressions):
345 | not_found = set()
346 | self.expressions = list(expressions)
347 | for exp in self.expressions:
348 | self.exp_dict[exp[1]] = exp[2]
349 | def expandAll(self):
350 | for exp in self.expressions:
351 | self.expandVariable(exp[1])
352 | def expandVariable(self, key):
353 | varToExpand = self.exp_dict[key]
354 | needToTestFuther = False
355 | for match in self.VAR_PATTERN.finditer(varToExpand):
356 | variable = match.groupdict()['key']
357 | if variable in self.exp_dict:
358 | replace_string = self.exp_dict[variable]
359 | varToExpand = varToExpand.replace('$(%s)' % variable, replace_string)
360 | needToTestFuther = True
361 | else:
362 | print('Cannot find variable: %s in expression %s' % (variable,key))
363 | self.exp_dict[key] = varToExpand
364 | if needToTestFuther:
365 | self.expandVariable(key)
366 |
--------------------------------------------------------------------------------
/Settings/QlikView script.sublime-completions:
--------------------------------------------------------------------------------
1 | {
2 | "scope": "source.qvs" ,
3 | "completions":
4 | [
5 | {"trigger": "Acos", "contents": "Acos(${1:x})$0"},
6 | {"trigger": "AddMonths", "contents": "AddMonths(${1:startdate}, ${2:n})$0"},
7 | {"trigger": "Aggr", "contents": "Aggr(${1:expression}, ${2:dimension})$0"},
8 | {"trigger": "Alt", "contents": "Alt(${1:case1}, ${2:else})$0"},
9 | {"trigger": "ApplyMap", "contents": "ApplyMap('${1:mapname}', ${2:expr}, ${3:defaultexpr})$0"},
10 | {"trigger": "ARGB", "contents": "ARGB(${1:alpha}, ${2:e1}, ${3:e2}, ${4:e3})$0"},
11 | {"trigger": "Asin", "contents": "Asin(${1:x})$0"},
12 | {"trigger": "Atan", "contents": "Atan(${1:x})$0"},
13 | {"trigger": "Atan2", "contents": "Atan2(${1:x,}, ${2:y})$0"},
14 | {"trigger": "Autonumber", "contents": "Autonumber(${1:expression}, '${2:AutoID}')$0"},
15 | {"trigger": "AutonumberHash128", "contents": "AutonumberHash128(${1:expression})$0"},
16 | {"trigger": "AutonumberHash256", "contents": "AutonumberHash256(${1:expression})$0"},
17 | {"trigger": "Avg", "contents": "Avg(${1:expression})$0"},
18 | {"trigger": "Avg", "contents": "Avg(${1:expression})$0"},
19 | {"trigger": "BitCount", "contents": "BitCount(${1:x})$0"},
20 | {"trigger": "Ceil", "contents": "Ceil(${1:x})$0"},
21 | {"trigger": "Chr", "contents": "Chr(${1:n})$0"},
22 | {"trigger": "Combin", "contents": "Combin(${1:n1},${2:n2})$0"},
23 | {"trigger": "Concat", "contents": "Concat(${1:expression}, ${2:delimiter}, ${3:sort})$0"},
24 | {"trigger": "Cos", "contents": "Cos(${1:x})$0"},
25 | {"trigger": "Cosh", "contents": "Cosh(${1:x})$0"},
26 | {"trigger": "Count", "contents": "Count(${1:expression})$0"},
27 | {"trigger": "Div", "contents": "Div(${1:x1}, ${2:x2})$0"},
28 | {"trigger": "Even", "contents": "Even(x)(${1:x})$0"},
29 | {"trigger": "Exp", "contents": "Exp(${1:x})$0"},
30 | {"trigger": "Fabs", "contents": "Fabs(${1:x})$0"},
31 | {"trigger": "Fact", "contents": "Fact(${1:x})$0"},
32 | {"trigger": "FieldValueCount", "contents": "FieldValueCount('${1:fieldName}')$0"},
33 | {"trigger": "FirstSortedValue", "contents": "FirstSortedValue('${1:expression}', ${2:sort-weight}, ${3:n})$0"},
34 | {"trigger": "FirstValue", "contents": "FirstValue(${1:expression})$0"},
35 | {"trigger": "Floor", "contents": "Floor(${1:x})$0"},
36 | {"trigger": "FMod", "contents": "FMod(${1:x1},${2:x2})$0"},
37 | {"trigger": "frac", "contents": "frac(${1:x})$0"},
38 | {"trigger": "If", "contents": "If(${1:condition}, ${2:then}, ${3:else})$0"},
39 | {"trigger": "IterNo", "contents": "IterNo()$0"},
40 | {"trigger": "LastValue", "contents": "LastValue(${1:expression})$0"},
41 | {"trigger": "Left", "contents": "Left(${1:string}, ${2:n})$0"},
42 | {"trigger": "Log", "contents": "Log(${1:x})$0"},
43 | {"trigger": "Log10", "contents": "Log10(${1:x})$0"},
44 | {"trigger": "Lookup", "contents": "Lookup('${1:field_name}', '${2:match_field_name}', ${3:match_field_value},'${4:table_name}')$0"},
45 | {"trigger": "Max", "contents": "Max(${1:expression})$0"},
46 | {"trigger": "MaxString", "contents": "MaxString(${1:expression})$0"},
47 | {"trigger": "Min", "contents": "Min(${1:expression})$0"},
48 | {"trigger": "MinString", "contents": "MinString(${1:expression})$0"},
49 | {"trigger": "MissingCount", "contents": "MissingCount(${1:expression})$0"},
50 | {"trigger": "Mod", "contents": "Mod(${1:x1},${2:x2})$0"},
51 | {"trigger": "Mode", "contents": "Mode(${1:expression})$0"},
52 | {"trigger": "NullCount", "contents": "NullCount(${1:expression})$0"},
53 | {"trigger": "NumericCount", "contents": "NumericCount(${1:expression})$0"},
54 | {"trigger": "Odd", "contents": "Odd(${1:x})$0"},
55 | {"trigger": "Only", "contents": "Only(${1:expression})$0"},
56 | {"trigger": "Ord", "contents": "Ord(${1:str})$0"},
57 | {"trigger": "Permut", "contents": "Permut(${1:n1},${2:n2})$0"},
58 | {"trigger": "Pow", "contents": "Pow(${1:x}, ${2:y})$0"},
59 | {"trigger": "RangeAvg", "contents": "RangeAvg(${1:expr1}, ${2:expr2})$0"},
60 | {"trigger": "RangeCorrel", "contents": "RangeCorrel(${1:x-value}, ${2:y-value})$0"},
61 | {"trigger": "RangeCount", "contents": "RangeCount(${1:expr1}, ${2:expr2})$0"},
62 | {"trigger": "RangeFractile", "contents": "RangeFractile(${1:expr1}, ${2:expr2})$0"},
63 | {"trigger": "RangeKurtosis", "contents": "RangeKurtosis(${1:expr1}, ${2:expr2})$0"},
64 | {"trigger": "RangeMax", "contents": "RangeMax(${1:expr1}, ${2:expr2})$0"},
65 | {"trigger": "RangeMaxString", "contents": "RangeMaxString(${1:expr1}, ${2:expr2})$0"},
66 | {"trigger": "RangeMin", "contents": "RangeMin(${1:expr1}, ${2:expr2})$0"},
67 | {"trigger": "RangeMinString", "contents": "RangeMinString(${1:expr1}, ${2:expr2})$0"},
68 | {"trigger": "RangeMissingCount", "contents": "RangeMissingCount(${1:expr1}, ${2:expr2})$0"},
69 | {"trigger": "RangeMode", "contents": "RangeMode(${1:expr1}, ${2:expr2})$0"},
70 | {"trigger": "RangeNullCount", "contents": "RangeNullCount(${1:expr1}, ${2:expr2})$0"},
71 | {"trigger": "RangeNumericCount", "contents": "RangeNumericCount(${1:expr1}, ${2:expr2})$0"},
72 | {"trigger": "RangeOnly", "contents": "RangeOnly(${1:expr1}, ${2:expr2})$0"},
73 | {"trigger": "RangeSkew", "contents": "RangeSkew(${1:expr1}, ${2:expr2})$0"},
74 | {"trigger": "RangeStdev", "contents": "RangeStdev(${1:expr1}, ${2:expr2})$0"},
75 | {"trigger": "RangeSum", "contents": "RangeSum(${1:expr1}, ${2:expr2})$0"},
76 | {"trigger": "RangeTextCount", "contents": "RangeTextCount(${1:expr1}, ${2:expr2})$0"},
77 | {"trigger": "RecNo", "contents": "RecNo()$0"},
78 | {"trigger": "Right", "contents": "Right(${1:string}, ${2:n})$0"},
79 | {"trigger": "Round", "contents": "Round(${1:x})$0"},
80 | {"trigger": "RowNo", "contents": "RowNo()$0"},
81 | {"trigger": "Sign", "contents": "Sign(${1:x})$0"},
82 | {"trigger": "Sin", "contents": "Sin(${1:x})$0"},
83 | {"trigger": "Sinh", "contents": "Sinh(${1:x})$0"},
84 | {"trigger": "Sqr", "contents": "Sqr(${1:x})$0"},
85 | {"trigger": "Sqrt", "contents": "Sqrt(${1:x})$0"},
86 | {"trigger": "Sum", "contents": "Sum(${1:expression})$0"},
87 | {"trigger": "Tan", "contents": "Tan(${1:x})$0"},
88 | {"trigger": "Tanh", "contents": "Tanh(${1:x})$0"},
89 | {"trigger": "TextCount", "contents": "TextCount(${1:expression})$0"},
90 | {"trigger": "Chr", "contents": "Chr(${1:n})$0"},
91 | {"trigger": "Len", "contents": "Len(${1:str})$0"},
92 | {"trigger": "Mid", "contents": "Mid(${1:str},${2:startPos},${3:len} )$0"},
93 | {"trigger": "Index", "contents": "Index(${1:str},${2:subStr})$0"},
94 | {"trigger": "Upper", "contents": "Upper(${1:str})$0"},
95 | {"trigger": "Lower", "contents": "Lower(${1:str})$0"},
96 | {"trigger": "Repeat", "contents": "Repeat(${1:str}, ${2:nTimes})$0"},
97 | {"trigger": "Ltrim", "contents": "Ltrim(${1:str})$0"},
98 | {"trigger": "Rtrim", "contents": "Rtrim(${1:str})$0"},
99 | {"trigger": "Subfield", "contents": "Subfield(${1:str},${2:delimiter},${3:index} )$0"},
100 | {"trigger": "KeepChar", "contents": "KeepChar(${1:str},${2:subStr})$0"},
101 | {"trigger": "PurgeChar", "contents": "PurgeChar(${1:str},${2:subStr})$0"},
102 | {"trigger": "Capitalize", "contents": "Capitalize(${1:str})$0"},
103 | {"trigger": "Evaluate", "contents": "Evaluate(${1:str})$0"},
104 | {"trigger": "TextBetween", "contents": "TextBetween(${1:str},${2:beforeText},${3:afterText})$0"},
105 | {"trigger": "Replace", "contents": "Replace(${1:str},${2:fromString},${3:toString})$0"},
106 | {"trigger": "FindOneOf", "contents": "FindOneOf(${1:text},${2:characterset})$0"},
107 | {"trigger": "Hash128", "contents": "Hash128(${1:expression},${2:moreExpressions})$0"},
108 | {"trigger": "Hash256", "contents": "Hash256(${1:expression},${2:moreExpressions})$0"},
109 | {"trigger": "SubstringCount", "contents": "SubstringCount(${1:text},${2:substring})$0"},
110 | {"trigger": "ApplyCodepage", "contents": "ApplyCodepage(${1:text},${2:nCodepage})$0"},
111 | {"trigger": "MapSubstring", "contents": "MapSubstring('${1:mapName}',${2:expr})$0"},
112 | {"trigger": "Pick", "contents": "Pick('${1:n}',${2:expr1},${3:expr2})$0"},
113 | {"trigger": "Match", "contents": "Match('${1:str}',${2:expr1},${3:expr2})$0"},
114 | {"trigger": "MixMatch", "contents": "MixMatch('${1:str}',${2:expr1},${3:expr2})$0"},
115 | {"trigger": "WildMatch", "contents": "WildMatch('${1:str}',${2:expr1},${3:expr2})$0"},
116 | {"trigger": "Class", "contents": "Class('${1:expression}',${2:interval},${3:label_optional},${4:interval_optional})$0"},
117 | {"trigger": "Null", "contents": "Null()$0"},
118 | {"trigger": "IsNull", "contents": "IsNull(${1:expr})$0"},
119 | {"trigger": "ClientPlatform", "contents": "ClientPlatform()$0"},
120 | {"trigger": "OSuser", "contents": "OSuser()$0"},
121 | {"trigger": "QVuser", "contents": "QVuser()$0"},
122 | {"trigger": "ComputerName", "contents": "ComputerName()$0"},
123 | {"trigger": "ReloadTime", "contents": "ReloadTime()$0"},
124 | {"trigger": "GetRegistryString", "contents": "GetRegistryString('${1:path}','${2:key}')$0"},
125 | {"trigger": "QlikViewVersion", "contents": "QlikViewVersion()$0"},
126 | {"trigger": "DocumentName", "contents": "DocumentName()$0"},
127 | {"trigger": "DocumentName", "contents": "DocumentName()$0"},
128 | {"trigger": "MapSubstring", "contents": "MapSubstring('${1:mapName}',${2:expr})$0"},
129 | {"trigger": "Second", "contents": "Second(${1:expression})$0"},
130 | {"trigger": "Minute", "contents": "Minute(${1:expression})$0"},
131 | {"trigger": "Hour", "contents": "Hour(${1:expression})$0"},
132 | {"trigger": "Day", "contents": "Day(${1:date})$0"},
133 | {"trigger": "Week", "contents": "Week(${1:date})$0"},
134 | {"trigger": "Month", "contents": "Month(${1:date})$0"},
135 | {"trigger": "Year", "contents": "Year(${1:date})$0"},
136 | {"trigger": "WeekYear", "contents": "WeekYear(${1:date})$0"},
137 | {"trigger": "WeekDay", "contents": "WeekDay(${1:date})$0"},
138 | {"trigger": "Now", "contents": "Now(${1:1})$0"},
139 | {"trigger": "Today", "contents": "Today(${1:2})$0"},
140 | {"trigger": "LocalTime", "contents": "LocalTime()"},
141 | {"trigger": "MakeDate", "contents": "MakeDate(${1:Year},${2:Month},${3:Day})$0"},
142 | {"trigger": "MakeWeekDate", "contents": "MakeWeekDate(${1:Year},${2:Week},${3:Day})$0"},
143 | {"trigger": "MakeTime", "contents": "MakeTime(${1:Hour},${2:Minute},${3:Second})$0"},
144 | {"trigger": "AddMonths", "contents": "AddMonths(${1:startDate},${2:n})$0"},
145 | {"trigger": "YearToDate", "contents": "YearToDate(${1:date},${2:yearOffset},${3:firstmonth},${4:todayDate})$0"},
146 | {"trigger": "TimeZone", "contents": "TimeZone()$0"},
147 | {"trigger": "UTC", "contents": "UTC()$0"},
148 | {"trigger": "GMT", "contents": "GMT()$0"},
149 | {"trigger": "DaylightSaving", "contents": "DaylightSaving()$0"},
150 | {"trigger": "SetDateYearMonth", "contents": "SetDateYearMonth(${1:timestamp},${2:year},${3:month})$0"},
151 | {"trigger": "SetDateYear", "contents": "SetDateYear(${1:timestamp},${2:year})$0"},
152 | {"trigger": "InYear", "contents": "InYear(${1:date},${2:basedate},${3:shift},${4:first_month_of_year})$0"},
153 | {"trigger": "InYearToDate", "contents": "InYearToDate(${1:date},${2:basedate},${3:shift},${4:first_month_of_year})$0"},
154 | {"trigger": "InQuarter", "contents": "InQuarter(${1:date},${2:basedate},${3:shift},${4:first_month_of_year})$0"},
155 | {"trigger": "InQuarterToDate", "contents": "InQuarterToDate(${1:date},${2:basedate},${3:shift},${4:first_month_of_year})$0"},
156 | {"trigger": "InMonth", "contents": "InQuarter(${1:date},${2:basedate},${3:shift})$0"},
157 | {"trigger": "InMonthToDate", "contents": "InQuarterToDate(${1:date},${2:basedate},${3:shift})$0"},
158 | {"trigger": "InMonths", "contents": "InMonths(${1:n},${2:date},${3:basedate},${4:shift},${5:first_month_of_year})$0"},
159 | {"trigger": "InMonthsToDate", "contents": "InMonthsToDate(${1:n},${2:date},${3:basedate},${4:shift},${5:first_month_of_year})$0"},
160 | {"trigger": "InWeek", "contents": "InWeek(${1:date},${2:basedate},${3:shift},${4:weekstart})$0"},
161 | {"trigger": "InWeekToDate", "contents": "InWeekToDate(${1:date},${2:basedate},${3:shift},${4:weekstart})$0"},
162 | {"trigger": "InLunarWeek", "contents": "InLunarWeek(${1:date},${2:basedate},${3:shift},${4:weekstart})$0"},
163 | {"trigger": "InLunarWeekToDate", "contents": "InLunarWeekToDate(${1:date},${2:basedate},${3:shift},${4:weekstart})$0"},
164 | {"trigger": "InDay", "contents": "InDay(${1:timestamp},${2:basetimestamp},${3:shift},${4:daystart})$0"},
165 | {"trigger": "InDayToTime", "contents": "InDayToTime(${1:timestamp},${2:basetimestamp},${3:shift},${4:daystart})$0"},
166 | {"trigger": "YearStart", "contents": "YearStart(${1:date},${2:shift})$0"},
167 | {"trigger": "YearEnd", "contents": "YearEnd(${1:date},${2:shift},${3:first_month_of_year})$0"},
168 | {"trigger": "YearName", "contents": "YearName(${1:date},${2:shift},${3:first_month_of_year})$0"},
169 | {"trigger": "QuarterStart", "contents": "QuarterStart(${1:date},${2:shift},${3:first_month_of_year})$0"},
170 | {"trigger": "QuarterEnd", "contents": "QuarterEnd(${1:date},${2:shift},${3:first_month_of_year})$0"},
171 | {"trigger": "QuarterName", "contents": "QuarterName(${1:date},${2:shift},${3:first_month_of_year})$0"},
172 | {"trigger": "MonthStart", "contents": "MonthStart(${1:date},${2:shift})$0"},
173 | {"trigger": "MonthEnd", "contents": "MonthEnd(${1:date},${2:shift})$0"},
174 | {"trigger": "MonthName", "contents": "MonthName(${1:date},${2:shift})$0"},
175 | {"trigger": "MonthsStart", "contents": "MonthsStart(${1:n},${2:date},${3:shift},${4:first_month_of_year})$0"},
176 | {"trigger": "MonthsEnd", "contents": "MonthsEnd(${1:n},${2:date},${3:shift},${4:first_month_of_year})$0"},
177 | {"trigger": "MonthsName", "contents": "MonthsName(${1:n},${2:date},${3:shift},${4:first_month_of_year})$0"},
178 | {"trigger": "WeekStart", "contents": "WeekStart(${1:date},${2:shift},${3:weekoffset})$0"},
179 | {"trigger": "WeekEnd", "contents": "WeekEnd(${1:date},${2:shift},${3:weekoffset})$0"},
180 | {"trigger": "WeekName", "contents": "WeekName(${1:date},${2:shift},${3:weekoffset})$0"},
181 | {"trigger": "LunarWeekStart", "contents": "LunarWeekStart(${1:date},${2:shift},${3:weekoffset})$0"},
182 | {"trigger": "LunarWeekEnd", "contents": "LunarWeekEnd(${1:date},${2:shift},${3:weekoffset})$0"},
183 | {"trigger": "LunarWeekName", "contents": "LunarWeekName(${1:date},${2:shift},${3:weekoffset})$0"},
184 | {"trigger": "WeekStart", "contents": "WeekStart(${1:timestamp},${2:shift},${3:dayoffset})$0"},
185 | {"trigger": "DayEnd", "contents": "DayEnd(${1:timestamp},${2:shift},${3:dayoffset})$0"},
186 | {"trigger": "DayName", "contents": "DayName(${1:timestamp},${2:shift},${3:dayoffset})$0"},
187 | {"trigger": "Age", "contents": "Age(${1:timestamp},${2:date_of_birth})$0"},
188 | {"trigger": "NetWorkdays", "contents": "NetWorkdays(${1:startDate},${2:endDate},${3:holiday})$0"},
189 | {"trigger": "FirstWorkdate", "contents": "FirstWorkdate(${1:end_date},${2:no_of_workdays},${3:holiday})$0"},
190 | {"trigger": "LastWorkdate", "contents": "LastWorkdate(${1:start_date},${2:no_of_workdays},${3:holiday})$0"},
191 | {"trigger": "ConvertToLocalTime", "contents": "ConvertToLocalTime(${1:timestamp},${2:place},${3:ignore_dst})$0"},
192 | {"trigger": "DayNumberOfYear", "contents": "DayNumberOfYear(${1:date},${2:firstmonth})$0"},
193 | {"trigger": "DayNumberOfQuarter", "contents": "DayNumberOfQuarter(${1:date},${2:firstmonth})$0"},
194 | {"trigger": "Money", "contents": "Money(${1:expression},'${2:format_code}')$0"},
195 | {"trigger": "Num", "contents": "Num(${1:expression})$0"},
196 | {"trigger": "Date", "contents": "Date(${1:expression})$0"},
197 | {"trigger": "Time", "contents": "Time(${1:expression},'${2:format_code}')$0"},
198 | {"trigger": "Dual", "contents": "Dual('${1:text}',${2:number})$0"},
199 | {"trigger": "Interval", "contents": "Interval(${1:expression},'${2:format_code}')$0"},
200 | {"trigger": "Timestamp", "contents": "Timestamp(${1:expression},'${2:format_code}')$0"},
201 | {"trigger": "Color", "contents": "Color(${1:n})$0"},
202 | {"trigger": "RGB", "contents": "RGB(${1:rExpr},${2:gExpr},${3:bExpr})$0"},
203 | {"trigger": "ARGB", "contents": "ARGB(${1:alfa},${2:rExpr},${3:gExpr},${4:bExpr})$0"},
204 | {"trigger": "HSL", "contents": "HSL(${1:hue},${2:saturation},${3:luminosity})$0"},
205 | {"trigger": "Black", "contents": "Black()$0"},
206 | {"trigger": "DarkGray", "contents": "DarkGray()$0"},
207 | {"trigger": "LightGray", "contents": "LightGray()$0"},
208 | {"trigger": "White", "contents": "White()$0"},
209 | {"trigger": "Blue", "contents": "Blue()$0"},
210 | {"trigger": "LightBlue", "contents": "LightBlue()$0"},
211 | {"trigger": "Green", "contents": "Green()$0"},
212 | {"trigger": "LightGreen", "contents": "LightGreen()$0"},
213 | {"trigger": "Cyan", "contents": "Cyan()$0"},
214 | {"trigger": "LightCyan", "contents": "LightCyan()$0"},
215 | {"trigger": "Red", "contents": "Red()$0"},
216 | {"trigger": "Magenta", "contents": "Magenta()$0"},
217 | {"trigger": "LightMagenta", "contents": "LightMagenta()$0"},
218 | {"trigger": "Brown", "contents": "Brown()$0"},
219 | {"trigger": "Yellow", "contents": "Yellow()$0"},
220 | {"trigger": "QliktechBlue", "contents": "QliktechBlue()$0"},
221 | {"trigger": "QliktechGray", "contents": "QliktechGray()$0"},
222 | {"trigger": "Colormix1", "contents": "HSL(${1:Value},${2:ColorZero},${3:ColorOne})$0"},
223 | {"trigger": "Colormix2", "contents": "HSL(${1:Value},${2:ColorMinusOne},${3:ColorOne},${4:ColorZeroOptional})$0"},
224 | {"trigger": "SysColor", "contents": "SysColor(${1:n})$0"},
225 | {"trigger": "FieldValueCount", "contents": "FieldValueCount('${1:fieldName}')$0"}
226 | ]
227 | }
--------------------------------------------------------------------------------
/Syntax/QlikView script.tmLanguage:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | fileTypes
6 |
7 | qvs
8 |
9 | name
10 | QlikView script file
11 | patterns
12 |
13 |
14 | include
15 | #subroutine
16 |
17 |
18 | include
19 | #null_assignment
20 |
21 |
22 | include
23 | #assignment
24 |
25 |
26 | include
27 | #tab
28 |
29 |
30 | include
31 | #comments
32 |
33 |
34 | include
35 | #strings
36 |
37 |
38 | include
39 | #numericLiterals
40 |
41 |
42 | include
43 | #variables
44 |
45 |
46 | include
47 | #qualifiers
48 |
49 |
50 | include
51 | #functions
52 |
53 |
54 | include
55 | #keyword
56 |
57 |
58 | include
59 | #operators
60 |
61 |
62 | include
63 | #tableIdentifiers
64 |
65 |
66 | include
67 | #braces
68 |
69 |
70 | repository
71 |
72 | assignment
73 |
74 | patterns
75 |
76 |
77 | captures
78 |
79 | 1
80 |
81 | name
82 | keyword.control.qvs
83 |
84 | 2
85 |
86 | name
87 | entity.name.type.variable.qvs
88 |
89 |
90 | match
91 | ^\s*([LlSs][Ee][Tt])\s+((\w|\.)+)\s*=
92 |
93 |
94 |
95 | braces
96 |
97 | patterns
98 |
99 |
100 | begin
101 | \(
102 | beginCaptures
103 |
104 | 0
105 |
106 | name
107 | support.constant.qvs
108 |
109 |
110 | end
111 | \)
112 | endCaptures
113 |
114 | 0
115 |
116 | name
117 | support.constant.qvs
118 |
119 |
120 | patterns
121 |
122 |
123 | include
124 | #fileQualifiers
125 |
126 |
127 | include
128 | #functions
129 |
130 |
131 | include
132 | #variables
133 |
134 |
135 | include
136 | #braces
137 |
138 |
139 | include
140 | #strings
141 |
142 |
143 | include
144 | #numericLiterals
145 |
146 |
147 |
148 |
149 |
150 | comments
151 |
152 | patterns
153 |
154 |
155 | begin
156 | //
157 | end
158 | $\n
159 | name
160 | comment.line.double-dash.source.qvs
161 |
162 |
163 | begin
164 | ^\s*REM
165 | end
166 | $\n
167 | name
168 | comment.line.rem.source.qvs
169 |
170 |
171 | begin
172 | /\*
173 | end
174 | \*/
175 | name
176 | comment.block.source.qvs
177 |
178 |
179 |
180 | fileQualifiers
181 |
182 | patterns
183 |
184 |
185 | match
186 | (?i)(?<=\s|\(|,)(codepage is \d+|ansi|oem|mac|utf8|unicode|qvd|qvx|txt|fix|dif|biff|html|delimiter is|no eof|no quotes|msq|xmlsax|xmlsimple|no labels|embedded labels|explicit labels|no eof|msq|header is (\d+ lines)?|record is (\d+ lines)?)|table is
187 | name
188 | support.constant.qvs
189 |
190 |
191 |
192 | functions
193 |
194 | patterns
195 |
196 |
197 | begin
198 | (?i)(\b|=)(if|getselectedcount|aggr|left|right|acos|addmonths|addyears|age|alt|applycodepage|applymap|argb|asin|atan|atan2|attribute|author|autonumber|autonumberhash128|autonumberhash256|avg|bitcount|black|blackandschole|blue|brown|capitalize|ceil|chi2test_chi2|chi2test_df|chi2test_p|chidist|chiinv|chr|class|clientplatform|color|colormaphue|colormapjet|colormix1|colormix2|combin|computername|concat|connectstring|converttolocaltime|correl|cos|cosh|count|cyan|darkgray|date|date#|day|dayend|daylightsaving|dayname|daynumberofquarter|daynumberofyear|daystart|div|DocumentName|DocumentPath|DocumentTitle|Dual|e|Evaluate|Even|Exists|exp|fabs|Fact|False|FDIST|FieldIndex|FieldName|FieldNumber|FieldValue|FieldValueCount|FileBaseName|FileDir|FileExtension|FileName|FilePath|FileSize|FileTime|FindOneOf|FINV|FirstSortedValue|FirstValue|FirstWorkDate|Floor|fmod|Frac|Fractile|FV|GetExtendedProperty|GetFolderPath|GetObjectField|GetRegistryString|GMT|Green|Hash128|Hash160|Hash256|Hour|HSL|InDay|InDayToTime|Index|InLunarWeek|InLunarWeekToDate|InMonth|InMonths|InMonthsToDate|InMonthToDate|Input|InputAvg|InputSum|InQuarter|InQuarterToDate|Interval|Interval#|InWeek|InWeekToDate|InYear|InYearToDate|IRR|IsNull|IsNum|IsPartialReload|IsText|IterNo|KeepChar|Kurtosis|LastValue|LastWorkDate|Len|LightBlue|LightCyan|LightGray|LightGreen|LightMagenta|LightRed|LINEST_B|LINEST_DF|LINEST_F|LINEST_M|LINEST_R2|LINEST_SEB|LINEST_SEM|LINEST_SEY|LINEST_SSREG|LINEST_SSRESID|LocalTime|log|log10|Lookup|Lower|LTrim|LunarWeekEnd|LunarWeekName|LunarWeekStart|Magenta|MakeDate|MakeTime|MakeWeekDate|MapSubString|Match|Max|MaxString|Median|Mid|Min|MinString|Minute|MissingCount|MixMatch|Mod|Mode|Money|Money#|Month|MonthEnd|MonthName|MonthsEnd|MonthsName|MonthsStart|MonthStart|MsgBox|NetWorkDays|NoOfFields|NoOfReports|NoOfRows|NoOfTables|NORMDIST|NORMINV|Now|nPer|NPV|Null|NullCount|Num|Num#|NumAvg|NumCount|NumericCount|NumMax|NumMin|NumSum|Odd|Only|Ord|OSUser|Peek|Permut|Pi|Pick|Pmt|pow|Previous|PurgeChar|PV|QlikTechBlue|QlikTechGray|QlikViewVersion|QuarterEnd|QuarterName|QuarterStart|QvdCreateTime|QvdFieldName|QvdNoOfFields|QvdNoOfRecords|QvdTableName|QVUser|Rand|RangeAvg|RangeCorrel|RangeCount|RangeFractile|RangeIRR|RangeKurtosis|RangeMax|RangeMaxString|RangeMin|RangeMinString|RangeMissingCount|RangeMode|RangeNPV|RangeNullCount|RangeNumericCount|RangeOnly|RangeSkew|RangeStdev|RangeSum|RangeTextCount|RangeXIRR|RangeXNPV|Rank|Rate|RecNo|Red|ReloadTime|Repeat|Replace|ReportComment|ReportId|ReportName|ReportNumber|RGB|Round|RowNo|RTrim|Second|SetDateYear|SetDateYearMonth|Sign|sin|sinh|Skew|sqr|sqrt|Stdev|Sterr|STEYX|SubField|SubStringCount|Sum|SysColor|TableName|TableNumber|tan|tanh|TDIST|Text|TextBetween|TextCount|Time|Time#|Timestamp|Timestamp#|TimeZone|TINV|Today|Trim|True|TTest1_conf|TTest1_df|TTest1_dif|TTest1_lower|TTest1_sig|TTest1_sterr|TTest1_t|TTest1_upper|TTest1w_conf|TTest1w_df|TTest1w_dif|TTest1w_lower|TTest1w_sig|TTest1w_sterr|TTest1w_t|TTest1w_upper|TTest_conf|TTest_df|TTest_dif|TTest_lower|TTest_sig|TTest_sterr|TTest_t|TTest_upper|TTestw_conf|TTestw_df|TTestw_dif|TTestw_lower|TTestw_sig|TTestw_sterr|TTestw_t|TTestw_upper|Upper|UTC|Week|WeekDay|WeekEnd|WeekName|WeekStart|WeekYear|White|WildMatch|WildMatch5|XIRR|XNPV|Year|Year2Date|YearEnd|YearName|YearStart|YearToDate|Yellow|ZTest_conf|ZTest_dif|ZTest_lower|ZTest_sig|ZTest_sterr|ZTest_upper|ZTest_z|ZTestw_conf|ZTestw_dif|ZTestw_lower|ZTestw_sig|ZTestw_sterr|ZTestw_upper|ZTestw_z)(\s*\()
199 | beginCaptures
200 |
201 | 2
202 |
203 | name
204 | entity.other.attribute-name.qvs
205 |
206 | 3
207 |
208 | name
209 | entity.other.attribute-name.qvs
210 |
211 |
212 | end
213 | \)
214 | endCaptures
215 |
216 | 0
217 |
218 | name
219 | entity.other.attribute-name.qvs
220 |
221 |
222 | patterns
223 |
224 |
225 | include
226 | #comments
227 |
228 |
229 | include
230 | #variables
231 |
232 |
233 | include
234 | #functions
235 |
236 |
237 | include
238 | #qualifiers
239 |
240 |
241 | include
242 | #numericLiterals
243 |
244 |
245 | include
246 | #operators
247 |
248 |
249 | include
250 | #strings
251 |
252 |
253 | include
254 | #braces
255 |
256 |
257 |
258 |
259 |
260 | keyword
261 |
262 | patterns
263 |
264 |
265 | captures
266 |
267 | 2
268 |
269 | name
270 | keyword.control.qvs
271 |
272 |
273 | match
274 | (?i)(^|\s)\b(SUB|NOT|OR|AND|ADD|ALIAS|ASC|BINARY|BUFFER|BUNDLE|CALL|COMMENT|CONCATENATE|CONNECT|CROSSTABLE|DESC|DIRECTORY|DISCONNECT|DO|DROP|EXECUTE|EACH|END|EXIT|FIELD|FIELDS|FIRST|FOR|FORCE|GENERIC|HIERARCHY|HIERARCHYBELONGSTO|THEN|ELSEIF|ELSE|ENDIF|IMAGE_SIZE|INFO|INNER|INPUTFIELD|INTERVALMATCH|JOIN|KEEP|LOAD|LOOSEN|MAPPING|MAP|USING|NOCONCATENATE|NULLASVALUE|NULLASNULL|OUTER|QUALIFY|RENAME|RIGHT|SAMPLE|SECTION|SELECT|SEMANTIC|SEMANTIC|SLEEP|SQL|SQLCOLUMNS|SQLTABLES|SQLTYPES|STAR|STORE|ENDSUB|SWITCH|CASE|DEFAULT|ENDSWITCH|TAG|TRACE|UNLESS|UNMAP|UNQUALIFY|UNTAG|WHEN|LOOP|NEXT|SCRIPT|TABLE|TABLES|FROM|INTO|AS|INTO|TO|STEP|AUTOGENERATE|RESIDENT|WHILE|WHERE|ORDER|GROUP|BY|WITH)\b
275 |
276 |
277 | captures
278 |
279 | 2
280 |
281 | name
282 | keyword.control.qvs
283 |
284 |
285 | match
286 | (?i)(^|\s)(LEFT|RIGHT|IF|REPLACE)(?!\()
287 |
288 |
289 |
290 | null_assignment
291 |
292 | patterns
293 |
294 |
295 | captures
296 |
297 | 1
298 |
299 | name
300 | keyword.control.qvs
301 |
302 |
303 | match
304 | ^\s*([LlSs][Ee][Tt])\s+(\w|\.)+\s*=\s*;
305 |
306 |
307 |
308 | numericLiterals
309 |
310 | patterns
311 |
312 |
313 | captures
314 |
315 | 1
316 |
317 | name
318 | constant.numeric.qvs
319 |
320 | 2
321 |
322 | name
323 | constant.numeric.qvs
324 |
325 |
326 | match
327 | (?<=\s|^|=|\(|,|>|<|\+|/|\*)(\-?\d+)(\.\d+)?
328 |
329 |
330 |
331 | operators
332 |
333 | patterns
334 |
335 |
336 | match
337 | (&|/)
338 | name
339 | keyword.control.qvs
340 |
341 |
342 | match
343 | (?i)\b(AND|OR)\b
344 | name
345 | keyword.control.qvs
346 |
347 |
348 |
349 | qualifiers
350 |
351 | patterns
352 |
353 |
354 | captures
355 |
356 | 1
357 |
358 | name
359 | keyword.control.qvs
360 |
361 |
362 | match
363 | (?i)(DISTINCT|TOTAL)(\s|<)
364 |
365 |
366 |
367 | strings
368 |
369 | patterns
370 |
371 |
372 | begin
373 | "
374 | end
375 | "
376 | name
377 | string.double.quoted.qvs
378 | patterns
379 |
380 |
381 | include
382 | #variables
383 |
384 |
385 |
386 |
387 | begin
388 | '
389 | end
390 | '
391 | name
392 | string.single.quoted.qvs
393 | patterns
394 |
395 |
396 | include
397 | #variables
398 |
399 |
400 |
401 |
402 | begin
403 | \[
404 | end
405 | \]
406 | name
407 | string.single.quoted.qvs
408 | patterns
409 |
410 |
411 | include
412 | #variables
413 |
414 |
415 |
416 |
417 |
418 | subroutine
419 |
420 | patterns
421 |
422 |
423 | captures
424 |
425 | 1
426 |
427 | name
428 | keyword.control.qvs
429 |
430 | 2
431 |
432 | name
433 | support.class entity.name.type.subroutine.qvs
434 |
435 |
436 | match
437 | ^\s*([Ss][Uu][Bb])\s+((?:\w|\.)+)
438 |
439 |
440 |
441 | tab
442 |
443 | patterns
444 |
445 |
446 | captures
447 |
448 | 1
449 |
450 | name
451 | comment.line.double-dash.source.qvs
452 |
453 | 2
454 |
455 | name
456 | support.constant.qvs meta.tab.qvs
457 |
458 |
459 | match
460 | ^(///\$tab) (.+)$
461 |
462 |
463 |
464 | tableIdentifiers
465 |
466 | patterns
467 |
468 |
469 | captures
470 |
471 | 2
472 |
473 | name
474 | support.constant.qvs entity.name.type.table.qvs
475 |
476 |
477 | match
478 | ^(\s)*(\w+):(\s)*$
479 | name
480 | support.constant.qvs
481 |
482 |
483 |
484 | variables
485 |
486 | patterns
487 |
488 |
489 | begin
490 | \$\(
491 | beginCaptures
492 |
493 | 0
494 |
495 | name
496 | variable.parameter.qvs
497 |
498 |
499 | end
500 | \)
501 | endCaptures
502 |
503 | 0
504 |
505 | name
506 | variable.parameter.qvs
507 |
508 |
509 | name
510 | variable.parameter.qvs
511 | patterns
512 |
513 |
514 | include
515 | #functions
516 |
517 |
518 | include
519 | #variables
520 |
521 |
522 | include
523 | #numericLiterals
524 |
525 |
526 | include
527 | #braces
528 |
529 |
530 |
531 |
532 | match
533 | \$\d+
534 | name
535 | variable.parameter.qvs
536 |
537 |
538 |
539 |
540 | scopeName
541 | source.qvs
542 | uuid
543 | 6b77dc03-7003-41f4-a9f6-287849f88d4f
544 |
545 |
546 |
--------------------------------------------------------------------------------