GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 8688ad...e355f5 )
by thatsIch
01:04
created

skins_path()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
c 2
b 0
f 0
dl 0
loc 4
rs 10
1
"""Module for getting Rainmeter-specific paths"""
2
3
import os
4
import re
5
6
import sublime
7
import sublime_plugin
8
9
# own dependencies
10
from . import logger
11
12
from .path.program_path_provider import get_cached_program_path
13
from .path.setting_path_provider import get_cached_setting_path
14
from .path.program_drive_provider import get_cached_program_drive
15
from .path.plugin_path_provider import get_cached_plugin_path
16
from .path.addon_path_provider import get_cached_addon_path
17
from .path.skin_path_provider import get_cached_skin_path
18
19
from .completion.completion import ContextSensAutoCompletion
20
21
22
def get_current_path(filepath):
23
    """Get the value of the #CURRENTPATH# variable for the specified path.
24
25
    Returns None if the file path is not in the skins folder
26
27
    """
28
29
    filepath = os.path.normpath(filepath)
30
31
    skinspath = get_cached_skin_path()
32
    if not skinspath or not filepath.startswith(skinspath):
33
        logger.info(__file__, "get_current_path", "current path could not be found because" +
34
                    " either the skins path could not be found or the current file" +
35
                    " is not located in the skins path.")
36
        return
37
38
    if os.path.isfile(filepath):
39
        return os.path.dirname(filepath) + "\\"
40
    else:
41
        return filepath + "\\"
42
43
44
def get_root_config_path(filepath):
45
    """Get the value of the #ROOTCONFIGPATH# variable for the specified path
46
47
    Returns None if the path is not in the skins folder
48
49
    """
50
51
    filepath = os.path.normpath(filepath)
52
53
    skinspath = get_cached_skin_path()
54
    if not skinspath or not filepath.startswith(skinspath):
55
        logger.info(__file__, "get_root_config_path", "root config path could not be found" +
56
                    " because either the skins path could not be found or the" +
57
                    " current file is not located in the skins path.")
58
        return
59
60
    relpath = os.path.relpath(filepath, skinspath)
61
    logger.info(__file__, "get_root_config_path",
62
                os.path.join(skinspath, relpath.split("\\")[0]) + "\\")
63
64
    return os.path.join(skinspath, relpath.split("\\")[0]) + "\\"
65
66
67
def get_current_file(filepath):
68
    """Get the value of the #CURRENTFILE# variable for the specified path
69
70
    Returns None if the path is not in the skins folder
71
72
    """
73
74
    filepath = os.path.normpath(filepath)
75
76
    skinspath = get_cached_skin_path()
77
    if not skinspath or not filepath.startswith(skinspath):
78
        logger.info(__file__, "get_current_file", "current file could not be found because" +
79
                    " either the skins path could not be found or the current" +
80
                    " file is not located in the skins path.")
81
        return
82
83
    if os.path.isfile(filepath):
84
        return os.path.basename(filepath)
85
    else:
86
        logger.info(__file__, "get_current_file", "specified path is not a file.")
87
        return
88
89
90
def get_current_config(filepath):
91
    """Get the value of the #CURRENTCONFIG# variable for the specified path
92
93
    Returns None if the path is not in the skins folder
94
95
    """
96
97
    filepath = os.path.normpath(filepath)
98
99
    skinspath = get_cached_skin_path()
100
    if not skinspath or not filepath.startswith(skinspath):
101
        logger.info(__file__, "get_current_config", "current config could not be found" +
102
                    " because \either the skins path could not be found or the" +
103
                    " current file is not located in the skins path.")
104
        return
105
106
    if os.path.isfile(filepath):
107
        filepath = os.path.dirname(filepath)
108
109
    return os.path.relpath(filepath, skinspath)
110
111
112
def get_resources_path(filepath):
113
    """Get the value of the #@# variable for the specified path
114
115
    Returns None if the path is not in the skins folder
116
117
    """
118
119
    rfp = get_root_config_path(filepath)
120
121
    if not rfp:
122
        return
123
    logger.info(__file__, "get_resources_path", os.path.join(rfp, "@Resources") + "\\")
124
    return os.path.join(rfp, "@Resources") + "\\"
125
126
127
def replace_variables(string, filepath):
128
    """Replace Rainmeter built-in variables and Windows environment variables
129
    in string.
130
131
    Replaces occurrences of the following variables in the string:
132
    #CURRENTFILE#
133
    #CURRENTPATH#
134
    #ROOTCONFIGPATH#
135
    #CURRENTCONFIG#
136
    #@#
137
    #SKINSPATH#
138
    #SETTINGSPATH#
139
    #PROGRAMPATH#
140
    #PROGRAMDRIVE#
141
    #ADDONSPATH#
142
    #PLUGINSPATH#
143
    Any Windows environment variables (like %APPDATA%)
144
    filepath must be a skin file located in a subdirectory of the skins folder
145
146
    """
147
148
    # lambdas for lazy evaluation
149
    variables = {"#CURRENTFILE#": lambda: get_current_file(filepath),
150
                 "#CURRENTPATH#": lambda: get_current_path(filepath),
151
                 "#ROOTCONFIGPATH#": lambda: get_root_config_path(filepath),
152
                 "#CURRENTCONFIG#": lambda: get_current_config(filepath),
153
                 "#@#": lambda: get_resources_path(filepath),
154
                 "#SKINSPATH#": get_cached_skin_path,
155
                 "#SETTINGSPATH#": get_cached_setting_path,
156
                 "#PROGRAMPATH#": get_cached_program_path,
157
                 "#PROGRAMDRIVE#": get_cached_program_drive,
158
                 "#ADDONSPATH#": get_cached_addon_path,
159
                 "#PLUGINSPATH#": get_cached_plugin_path}
160
161
    pattern = re.compile("(?i)" + "|".join(list(variables.keys())))
162
    # replace Rainmeter variables
163
    repl = pattern.sub(lambda x: variables[x.group().upper()](),
164
                       string)
165
    # expand windows environment variables
166
    repl = os.path.expandvars(repl)
167
    return repl
168
169
170
def make_path(string, filepath):
171
    """Make the string into an absolute path of an existing file or folder,
172
173
    replacing Rainmeter built-in variables relative to the file specified in
174
    filepath (see replace_variables()) will return None if the file or folder
175
    doesn't exist, or if string is None or empty.
176
177
    """
178
179
    if not string:
180
        return None
181
182
    repl = replace_variables(string, filepath)
183
    norm = os.path.normpath(repl)
184
185
    # For relative paths, try folder of current file first
186
187
    if not os.path.isabs(norm):
188
        curpath = get_current_path(filepath)
189
        if curpath:
190
            abso = os.path.join(curpath, norm)
191
        else:
192
            abso = os.path.join(os.path.dirname(filepath), norm)
193
194
        if os.path.exists(abso):
195
            return abso
196
197
        # if that doesn't work, try relative to skins path
198
        # (for #CURRENTCONFIG#)
199
        abso = os.path.join(get_cached_skin_path(), norm)
200
        if os.path.exists(abso):
201
            return abso
202
    # for absolute paths, try opening containing folder if file does not exist
203
    else:
204
        if os.path.exists(norm):
205
            return norm
206
207
        if os.path.exists(os.path.dirname(norm)):
208
            return os.path.dirname(norm)
209
210
    return
211
212
213
# Initialize Module
214
# Global Variables
215
settings = None
216
217
218
# Called automatically from ST3 if plugin is loaded
219
# Is required now due to async call and ignoring sublime.* from main routine
220
def plugin_loaded():
221
    # define variables from the global scope
222
    global settings
223
224
    global _skins_path
225
226
    settings = sublime.load_settings("Rainmeter.sublime-settings")
227
228
    logger.info(__file__, "plugin_loaded()", "#PROGRAMPATH#:\t\t" + get_cached_program_path())
229
    logger.info(__file__, "plugin_loaded()", "#PROGRAMDRIVE#:\t" + get_cached_program_drive())
230
    logger.info(__file__, "plugin_loaded()", "#SETTINGSPATH#:\t" + get_cached_setting_path())
231
    logger.info(__file__, "plugin_loaded()", "#SKINSPATH#:\t\t" + get_cached_skin_path())
232
    logger.info(__file__, "plugin_loaded()", "#PLUGINSPATH#:\t\t" + get_cached_plugin_path())
233
    logger.info(__file__, "plugin_loaded()", "#ADDONSPATH#:\t\t" + get_cached_addon_path())
234
235
236
class MeterAutoComplete(sublime_plugin.EventListener):
237
238
    # only show our completion list because nothing else makes sense in this context
239
    flags = sublime.INHIBIT_EXPLICIT_COMPLETIONS | sublime.INHIBIT_WORD_COMPLETIONS
240
    scope = "source.rainmeter"
241
242
    comment_exp = re.compile(r'^\s*;.*')
243
    meter_exp = re.compile(r'^\s*')
244
245
    completions = [
246
        # measures
247
        (re.compile(r'^\s*Measure\s*=\s*'), [
248
            # key, value
249
            ["Calc", "Calc"],
250
            ["CPU", "CPU"],
251
            ["FreeDiskSpace", "FreeDiskSpace"],
252
            ["Loop", "Loop"],
253
254
            # memory measure
255
            ["Memory", "Memory"],
256
            ["PhysicalMemory", "PhysicalMemory"],
257
            ["SwapMemory", "SwapMemory"],
258
259
            # net measure
260
            ["NetIn", "NetIn"],
261
            ["NetOut", "NetOut"],
262
            ["NetTotal", "NetTotal"],
263
264
            ["Plugin", "Plugin"],
265
            ["Registry", "Registry"],
266
            ["Script", "Script"],
267
            ["String", "String"],
268
            ["Time", "Time"],
269
            ["Uptime", "Uptime"]
270
        ]),
271
272
        # meters
273
        (re.compile(r'^\s*Meter\s*=\s*'), [
274
            # key, value
275
            ["Bar", "Bar"],
276
            ["Bitmap", "Bitmap"],
277
            ["Button", "Button"],
278
            ["Histogram", "Histogram"],
279
            ["Image", "Image"],
280
            ["Line", "Line"],
281
            ["Rotator", "Rotator"],
282
            ["Roundline", "Roundline"],
283
            ["Shape", "Shape"],
284
            ["String", "String"]
285
        ]),
286
        # general options
287
288
        # bar
289
        # bar orientation
290
        (re.compile(r'^\s*BarOrientation\s*=\s*'), [
291
            # key, value
292
            ["Horizontal", "Horizontal"],
293
            ["Vertical\tDefault", "Vertical"]
294
        ]),
295
296
        # bar flip
297
        (re.compile(r'^\s*Flip\s*=\s*'), [
298
            # key, value
299
            ["0\tDefault", "0"],
300
            ["1\tBar is flipped", "1"]
301
        ]),
302
303
        # bitmap
304
305
        # button
306
        # histogram
307
        # image
308
        # line
309
        # rotator
310
        # roundline
311
        # shape
312
        # string
313
314
        # plugins
315
        (re.compile(r'^\s*Plugin\s*=\s*'), [
316
            # key, value
317
            ["ActionTimer", "ActionTimer"],
318
            ["AdvancedCPU", "AdvancedCPU"],
319
            ["AudioLevel", "AudioLevel"],
320
            ["CoreTemp", "CoreTemp"],
321
            ["FileView", "FileView"],
322
            ["FolderInfo", "FolderInfo"],
323
            ["InputText", "InputText"],
324
            ["iTunes", "iTunesPlugin"],
325
            ["MediaKey", "MediaKey"],
326
            ["NowPlaying", "NowPlaying"],
327
            ["PerfMon", "PerfMon"],
328
            ["Ping", "PingPlugin"],
329
            ["Power", "PowerPlugin"],
330
            ["Process", "Process"],
331
            ["Quote", "QuotePlugin"],
332
            ["RecycleManager", "RecycleManager"],
333
            ["ResMon", "ResMon"],
334
            ["RunCommand", "RunCommand"],
335
            ["SpeedFan", "SpeedFanPlugin"],
336
            ["SysInfo", "SysInfo"],
337
            ["WebParser", "WebParser"],
338
            ["WiFiStatus", "WiFiStatus"],
339
            ["Win7Audio", "Win7AudioPlugin"],
340
            ["WindowMessage", "WindowMessagePlugin"]
341
        ]),
342
    ]
343
344
    def on_query_completions(self, view, prefix, locations):
345
        for location in locations:
346
            # checks if the current scope is correct so it is only called in the files with the correct scope
347
            # here is scope only rainmeter files
348
            if view.match_selector(location, self.scope):
349
                # find last occurance of the [] to determine the ini sections
350
                line = view.line(location)
351
                line_contents = view.substr(line)
352
353
                # starts with Measure, followed by an equal sign
354
                for exp, elements in self.completions:
355
                    if exp.search(line_contents):
356
                        return elements, self.flags
357
        return None
358
359
360
class CompletionProxy(sublime_plugin.EventListener):
361
362
    proxied_completion = None
363
364
    def __init__(self):
365
        self.proxied_completion = ContextSensAutoCompletion()
366
367
    def on_query_completions(self, view, prefix, locations):
368
        return self.proxied_completion.on_query_completions(view, prefix, locations)
369