11# -*- coding: utf-8 -*-
22# @Author: Lime
33# @Date: 2013-10-28 13:39:48
4- # @Last Modified by: Lime
5- # @Last Modified time: 2016-03-06 10:23:52
4+ # @Last Modified by: qkdreyer
5+ # @Last Modified time: 2017-08-14 16:48:32
66
77import os
88import sys
2828BODY_PATH = os .path .join (PLUGIN_PATH , 'template/body' )
2929INSTALLED_PLGIN_PATH = os .path .abspath (os .path .dirname (__file__ ))
3030
31+ FILE_SUFFIX_MAPPING = {
32+ "as" : "ActionScript" ,
33+ "scpt" : "AppleScript" ,
34+ "asp" : "ASP" ,
35+ "aspx" : "ASP" ,
36+ "bat" : "Batch File" ,
37+ "cmd" : "Batch File" ,
38+ "c" : "C" ,
39+ "cs" : "C#" ,
40+ "cpp" : "C++" ,
41+ "clj" : "Clojure" ,
42+ "css" : "CSS" ,
43+ "D" : "D" ,
44+ "erl" : "Erlang" ,
45+ "go" : "Go" ,
46+ "groovy" : "Groovy" ,
47+ "hs" : "Haskell" ,
48+ "htm" : "HTML" ,
49+ "html" : "HTML" ,
50+ "java" : "Java" ,
51+ "js" : "JavaScript" ,
52+ "tex" : "LaTeX" ,
53+ "lsp" : "Lisp" ,
54+ "lua" : "Lua" ,
55+ "md" : "Markdown" ,
56+ "mat" : "Matlab" ,
57+ "m" : "Objective-C" ,
58+ "ml" : "OCaml" ,
59+ "p" : "Pascal" ,
60+ "pl" : "Perl" ,
61+ "php" : "PHP" ,
62+ "py" : "Python" ,
63+ "R" : "R" ,
64+ "rst" : "RestructuredText" ,
65+ "rb" : "Ruby" ,
66+ "scala" : "Scala" ,
67+ "scss" : "SCSS" ,
68+ "sh" : "ShellScript" ,
69+ "sql" : "SQL" ,
70+ "tcl" : "TCL" ,
71+ "txt" : "Text" ,
72+ "xml" : "XML"
73+ }
74+
75+ HEADER_PREFIX_MAPPING = {
76+ "PHP" : "<?php\n \n "
77+ }
78+
79+ EXTENSION_EQUIVALENCE = {
80+ "blade.php" : "html"
81+ }
82+
83+ LANGUAGE_SYNTAX_MAPPING = {
84+ 'Graphviz' : 'DOT' ,
85+ 'RestructuredText' : 'reStructuredText' ,
86+ 'ShellScript' : 'Shell-Unix-Generic' ,
87+ 'TCL' : 'Tcl' ,
88+ 'Text' : 'Plain text'
89+ }
90+
3191IS_ST3 = sublime .version () >= '3'
3292
3393sys .path .insert (0 , PLUGIN_PATH )
@@ -85,6 +145,12 @@ def getOutputError(cmd):
85145 stdout = subprocess .PIPE , stderr = subprocess .PIPE ).communicate ())
86146
87147
148+ def View ():
149+ '''Get current active window view'''
150+
151+ return Window ().active_view ()
152+
153+
88154def Window ():
89155 '''Get current active window'''
90156
@@ -160,7 +226,7 @@ def get_user():
160226def get_project_name ():
161227 '''Get project name'''
162228
163- project_data = sublime . active_window ().project_data ()
229+ project_data = Window ().project_data ()
164230 project = os .path .basename (
165231 project_data ['folders' ][0 ]['path' ]) if project_data else None
166232
@@ -170,7 +236,7 @@ def get_project_name():
170236def get_dir_path ():
171237 '''Get current file dir path'''
172238
173- view , path = Window (). active_view (), None
239+ view , path = View (), None
174240 if view :
175241 file_name = view .file_name ()
176242 if file_name is not None :
@@ -285,8 +351,10 @@ def get_syntax_type(name):
285351 '''Judge `syntax_type` according to to `name`'''
286352
287353 syntax_type = Settings ().get ('syntax_when_not_match' )
288- file_suffix_mapping = Settings ().get ('file_suffix_mapping' )
289- extension_equivalence = Settings ().get ('extension_equivalence' )
354+ file_suffix_mapping = merge_defaults_with_settings (
355+ FILE_SUFFIX_MAPPING , 'file_suffix_mapping' )
356+ extension_equivalence = merge_defaults_with_settings (
357+ EXTENSION_EQUIVALENCE , 'extension_equivalence' )
290358
291359 if name is not None :
292360 name = name .split ('.' )
@@ -312,19 +380,69 @@ def get_syntax_type(name):
312380def get_syntax_file (syntax_type ):
313381 '''Get syntax file path'''
314382
315- lang2tmL = {
316- 'Graphviz' : 'DOT' ,
317- 'RestructuredText' : 'reStructuredText' ,
318- 'ShellScript' : 'Shell-Unix-Generic' ,
319- 'TCL' : 'Tcl' ,
320- 'Text' : 'Plain text' ,
321- }
322-
383+ # weird workaround
323384 if syntax_type == 'C' :
324385 syntax_type = 'C++'
325386
387+ lang2tmL = merge_defaults_with_settings (
388+ LANGUAGE_SYNTAX_MAPPING , 'language_syntax_mapping' )
326389 tmL = lang2tmL .get (syntax_type , syntax_type )
327- return 'Packages/%s/%s.tmLanguage' % (syntax_type , tmL )
390+
391+ if not '.' in tmL :
392+ tmL += '.tmLanguage'
393+
394+ return 'Packages/%s/%s' % (syntax_type , tmL )
395+
396+
397+ def get_content_index (haystack , needle ):
398+ '''Get the right needle position in haystack'''
399+ pos = haystack .find (needle )
400+ return pos + len (needle ) if pos >= 0 else 0
401+
402+
403+ def get_header_prefix (syntax_type , default = '' ):
404+ '''Get the header prefix'''
405+ header_prefix_mapping = merge_defaults_with_settings (
406+ HEADER_PREFIX_MAPPING , 'header_prefix_mapping' )
407+ try :
408+ return header_prefix_mapping .get (syntax_type , default )
409+ except KeyError :
410+ return default
411+
412+
413+ def get_header_content (syntax_type , path = None , file = None ):
414+ '''Get the correctly computed header content'''
415+ header_prefix = get_header_prefix (syntax_type )
416+ content = '' if isinstance (
417+ file , str ) and header_prefix in file else header_prefix
418+ return content + render_template (syntax_type , 'header' , {'path' : path })
419+
420+
421+ def get_file_content (file , syntax_type , header ):
422+ '''Get the correctly computed file content'''
423+ header_prefix = get_header_prefix (syntax_type )
424+ file_index = get_content_index (file , header_prefix )
425+ return file [0 :file_index ] + header + file [file_index :]
426+
427+
428+ def template_header_exists (file , syntax_type ):
429+ '''Return whether template header has been compiled in file'''
430+ template_header = get_template_part (syntax_type , 'header' ).strip ()
431+ regex = r'\\{\\{[a-z\\_]+\\}\\}'
432+ return re .search (re .sub (regex , '.*' , re .escape (template_header )), file )
433+
434+
435+ def merge_dicts (* dicts ):
436+ '''Merge any number of dicts into a new dict'''
437+ result = {}
438+ for dict in dicts :
439+ result .update (dict )
440+ return result
441+
442+
443+ def merge_defaults_with_settings (default , setting_name ):
444+ '''Merge default dict with package settings'''
445+ return merge_dicts (default , Settings ().get (setting_name , {}))
328446
329447
330448def block (view , callback , * args , ** kwargs ):
@@ -347,7 +465,7 @@ def new_file(self, path, syntax_type):
347465 sublime .error_message ('File exists!' )
348466 return
349467
350- header = render_template (syntax_type , options = { ' path' : path } )
468+ header = get_header_content (syntax_type , path )
351469
352470 try :
353471 with open (path , 'w+' ) as f :
@@ -357,18 +475,19 @@ def new_file(self, path, syntax_type):
357475 sublime .error_message (str (e ))
358476 return
359477
360- new_file = Window ().open_file (path )
478+ view = Window ().open_file (path )
479+ file_syntax = get_syntax_file (syntax_type )
361480
362- try :
363- block ( new_file ,
364- new_file .set_syntax_file , get_syntax_file ( syntax_type ) )
365- except :
366- pass
481+ if os . path . exists ( file_syntax ) and os . path . isfile ( file_syntax ) :
482+ try :
483+ block ( view , view .set_syntax_file , file_syntax )
484+ except :
485+ pass
367486
368- block (new_file , new_file .show , 0 )
487+ block (view , view .show , 0 )
369488
370489 def new_view (self , syntax_type , name ):
371- header = render_template (syntax_type )
490+ header = get_header_content (syntax_type )
372491 new_file = Window ().new_file ()
373492 new_file .set_name (name )
374493 new_file .run_command ('insert' , {'characters' : header })
@@ -422,14 +541,17 @@ def __init__(self, path):
422541
423542 def run (self ):
424543 syntax_type = get_syntax_type (self .path )
425- header = render_template (syntax_type , 'header' , {'path' : self .path })
426544
427545 try :
428546 with open (self .path , 'r' ) as f :
429- contents = header + f .read ()
547+ file = f .read ()
430548
431- with open (self .path , 'w' ) as f :
432- f .write (contents )
549+ if not template_header_exists (file , syntax_type ):
550+ header_content = get_header_content (
551+ syntax_type , self .path , file )
552+ contents = get_file_content (file , syntax_type , header_content )
553+ with open (self .path , 'w' ) as f :
554+ f .write (contents )
433555
434556 except Exception as e :
435557 sublime .error_message (str (e ))
@@ -448,8 +570,15 @@ def run(self, edit, path, part=None):
448570 c_time = pickle .loads (str (c_time ))
449571 options .update ({'c_time' : c_time })
450572
451- header = render_template (syntax_type , part , options )
452- self .view .insert (edit , 0 , header )
573+ view = View ()
574+ view_content = view .substr (sublime .Region (0 , view .size ()))
575+
576+ if not template_header_exists (view_content , syntax_type ):
577+ header_content = get_header_content (
578+ syntax_type , path , view_content )
579+ header_prefix = get_header_prefix (syntax_type )
580+ view_index = get_content_index (view_content , header_prefix )
581+ self .view .insert (edit , view_index , header_content )
453582
454583
455584class FileHeaderAddHeaderCommand (sublime_plugin .WindowCommand ):
@@ -509,7 +638,6 @@ def add(self, path):
509638
510639 whether_open_file = Settings ().get (
511640 'open_file_when_add_header_to_directory' )
512-
513641 if whether_open_file :
514642 modified_file = Window ().open_file (path )
515643 block (modified_file , modified_file .run_command ,
@@ -548,7 +676,7 @@ def run(self, paths=[]):
548676 initial_text = os .path .abspath (paths [0 ])
549677 else :
550678 try :
551- initial_text = Window ().active_view (). file_name ()
679+ initial_text = View ().file_name () or 'untitled'
552680 except :
553681 pass
554682
@@ -672,8 +800,21 @@ def on_text_command(self, view, command_name, args):
672800 view .run_command ('undo' )
673801
674802 def on_pre_save (self , view ):
803+ enable_add_template_on_save = Settings ().get (
804+ 'enable_add_template_on_save' , False )
805+ file_name = view .file_name ()
806+
807+ if isinstance (enable_add_template_on_save , str ):
808+ search = re .search (enable_add_template_on_save , file_name )
809+ enable_add_template_on_save = search != None
810+
811+ if enable_add_template_on_save :
812+ block (view , view .run_command ,
813+ 'add_file_header' , {'path' : file_name })
814+
675815 if view .id () in FileHeaderListener .new_view_id :
676- self .insert_template (view , False )
816+ if not enable_add_template_on_save :
817+ self .insert_template (view , False )
677818 index = FileHeaderListener .new_view_id .index (view .id ())
678819 del FileHeaderListener .new_view_id [index ]
679820 else :
0 commit comments