Sublime Text 2 est un éditeur de texte hautement personnalisable qui capte de plus en plus l’attention des développeurs qui recherchent un outil puissant, rapide et moderne. Aujourd'hui, nous allons recréer mon populaire plug-in Sublime qui envoie du CSS via l'API Nettuts + Prefixr pour faciliter le CSS entre navigateurs..
Une fois terminé, vous comprendrez parfaitement comment le plugin Sublime Prefixr est écrit et serez en mesure de commencer à écrire vos propres plugins pour l'éditeur.!
Le modèle d'extension de Sublime Text 2 est assez complet.
Le modèle d’extension de Sublime Text 2 est assez complet. Il y a moyen de changer la coloration syntaxique, le chrome actuel de l'éditeur et tous les menus. En outre, il est possible de créer de nouveaux systèmes de construction, auto-complétions, définitions de langage, extraits de code, macros, raccourcis clavier, raccourcis souris et plugins. Tous ces types de modifications sont implémentés via des fichiers organisés en packages..
Un paquet est un dossier qui est stocké dans votre Paquets
annuaire. Vous pouvez accéder à votre répertoire Packages en cliquant sur le bouton Préférences> Parcourir les packages… entrée de menu. Il est également possible de regrouper un package dans un seul fichier en créant un fichier zip et en modifiant l'extension en .sublime-package
. Nous allons discuter de l'emballage un peu plus loin dans ce tutoriel.
Sublime est livré avec un grand nombre de packages différents. La plupart des packages fournis sont spécifiques à une langue. Ceux-ci contiennent des définitions de langage, des auto-complétions et des systèmes de construction. Outre les packages linguistiques, il existe deux autres packages: Défaut
et Utilisateur
. leDéfaut
Le paquet contient toutes les raccourcis clavier, définitions de menus, paramètres de fichiers et tout un ensemble de plugins écrits en Python. le Utilisateur
Le paquet est spécial en ce sens qu'il est toujours chargé en dernier. Cela permet aux utilisateurs de remplacer les valeurs par défaut en personnalisant les fichiers de leur dossier. Utilisateur
paquet.
Lors de la rédaction d'un plugin, la référence de l'API Sublime Text 2 sera essentielle..
Lors de la rédaction d'un plugin, la référence de l'API Sublime Text 2 sera essentielle. De plus, le Défaut
Ce package constitue une bonne référence pour savoir comment faire les choses et ce qui est possible. Une grande partie des fonctionnalités de l'éditeur sont exposées via commandes. Toute opération autre que la saisie de caractères est effectuée via des commandes. En regardant le Préférences> Liaisons de touches - Par défautentrée de menu, il est possible de trouver un trésor de fonctionnalités intégrées.
Maintenant que la distinction entre un plugin et un paquet est claire, commençons à écrire notre plugin.
Sublime est livré avec une fonctionnalité qui génère un squelette du code Python nécessaire pour écrire un plugin simple. Sélectionnez le Outils> Nouveau plugin… entrée de menu, et un nouveau tampon sera ouvert avec ce warmplate.
import sublime, classe sublime_plugin ExampleCommand (sublime_plugin.TextCommand): def run (self, édition): self.view.insert (edit, 0, "Hello, World!")
Ici, vous pouvez voir que les deux modules Sublime Python sont importés pour permettre l'utilisation de l'API et qu'une nouvelle classe de commandes est créée. Avant de modifier ceci et de créer notre propre plugin, sauvegardons le fichier et activons la fonctionnalité intégrée..
Lorsque nous sauvegardons le fichier, nous allons créer un nouveau paquet pour le stocker. Appuyez sur ctrl + s (Windows / Linux) ou cmd + s (OS X) pour enregistrer le fichier. La boîte de dialogue de sauvegarde s’ouvrira au Utilisateur
paquet. Ne sauvegardez pas le fichier là-bas, mais parcourez un dossier et créez un nouveau dossier nommé Préfixe
.
Packages /… - OCaml / - Perl / - PHP / - Préfixe / - Python / - R / - Rails /…
Maintenant, enregistrez le fichier dans le dossier Prefixr en tant que Prefixr.py
. Le nom du fichier n'a pas d'importance, juste qu'il se termine par .py
. Cependant, par convention, nous utiliserons le nom du plugin pour le nom du fichier..
Maintenant que le plugin est enregistré, essayons-le. Ouvrez la console Sublime en appuyant sur ctrl + '. Ceci est une console Python qui a accès à l’API. Entrez le Python suivant pour tester le nouveau plugin:
view.run_command ('example')
Tu devrais voir Bonjour le monde
inséré au début du fichier plugin. Assurez-vous d'annuler ce changement avant de continuer..
Pour les plugins, Sublime fournit trois types de commandes différents.
Vue
objet La fenêtre
objet Puisque nous allons manipuler le contenu d’un fichier / tampon CSS avec ce plugin, nous allons utiliser le sublime_plugin.TextCommand
classe comme base de notre commande Prefixr personnalisée. Cela nous amène au sujet de la désignation des classes de commandes.
Dans le squelette de plug-in fourni par Sublime, vous remarquerez le cours:
Classe ExampleCommand (sublime_plugin.TextCommand):
Lorsque nous avons voulu exécuter la commande, nous avons exécuté le code suivant dans la console:
view.run_command ('example')
Sublime prendra n'importe quelle classe qui étend l'un des sublime_plugin
Des classes
(TextCommand
, WindowCommand
ou ApplicationCommand
), supprimez le suffixe Commander
puis convertir le Affaire de chameau
dans underscore_notation
pour le nom de la commande.
Ainsi, pour créer une commande avec le nom préfixe
, la classe doit être PrefixrCommand
.
classe PrefixrCommand (sublime_plugin.TextCommand):
Une des fonctionnalités les plus utiles de Sublime est la possibilité d’avoir plusieurs sélections..
Maintenant que notre plugin est nommé correctement, nous pouvons commencer le processus de récupération de CSS à partir du tampon actuel et de son envoi à l'API Prefixr. Une des fonctionnalités les plus utiles de Sublime est la possibilité d’avoir plusieurs sélections. Pendant que nous saisissons le texte sélectionné, nous devons écrire notre plug in handle, pas seulement la première sélection, mais toutes..
Depuis que nous écrivons une commande de texte, nous avons accès à la vue actuelle via auto.view
. le sel ()
méthode du Vue
objet retourne un itérable RégionSet
des sélections en cours. Nous commençons par les parcourir pour rechercher des accolades. Si les accolades ne sont pas présentes, nous pouvons élargir la sélection aux accolades environnantes pour que le bloc entier soit préfixé. Que notre sélection inclue ou non des accolades sera également utile ultérieurement pour savoir si nous pouvons modifier les espaces et la mise en forme du résultat obtenu par l'API Prefixr..
accolades = Faux sels = self.view.sel () pour les locations suivantes: si self.view.substr (sel) .find ('')! = -1: accolades = True
Ce code remplace le contenu du squelette courir()
méthode.
Si nous ne trouvons aucune accolade, nous passons en revue chaque sélection et ajustons les sélections à l'accolade fermante la plus proche. Ensuite, nous utilisons la commande intégrée expand_selection
avec le à
arg mis à supports
pour nous assurer que le contenu complet de chaque bloc CSS est sélectionné.
sinon accolades: new_sels = [] pour sel in sel: new_sels.append (self.view.find ('\', sel.end ())) sels.clear () pour sel dans new_sels: sels.add (sel ) self.view.run_command ("expand_selection", "à": "crochets")
Si vous souhaitez vérifier votre travail jusqu'ici, comparez la source au fichier. Prefixr-1.py
dans le fichier zip du code source.
Pour éviter qu'une mauvaise connexion n'interrompe un autre travail, nous devons nous assurer que les appels de l'API Prefixr se déroulent en arrière-plan..
À ce stade, les sélections ont été développées pour récupérer le contenu complet de chaque bloc CSS. Maintenant, nous devons les envoyer à l’API Prefixr. Ceci est une simple requête HTTP, que nous allons utiliser le urllib
et urllib2
modules pour. Cependant, avant de commencer à lancer des requêtes Web, nous devons réfléchir à la manière dont une requête Web potentiellement lente pourrait affecter les performances de l'éditeur. Si, pour une raison quelconque, l'utilisateur dispose d'une connexion à latence élevée ou lente, les demandes adressées à l'API Prefixr peuvent facilement prendre quelques secondes ou plus..
Pour éviter qu'une mauvaise connexion n'interrompe un autre travail, nous devons nous assurer que les appels de l'API Prefixr se déroulent en arrière-plan. Si vous ne connaissez rien au threading, une explication très simple est que les threads sont un moyen pour un programme de planifier l'exécution simultanée de plusieurs jeux de code. C'est essentiel dans notre cas car cela permet au code qui envoie des données à l'API Prefixr et attend une réponse de celle-ci d'empêcher le gel du reste de l'interface utilisateur Sublime..
Nous allons utiliser le Python filetage
module pour créer des threads. Pour utiliser le module de threading, nous créons une nouvelle classe qui s'étend threading.Thread
appelé PrefixrApiCall
. Des cours qui s'étendent threading.Thread
inclure un courir()
méthode qui contient tout le code à exécuter dans le thread.
classe PrefixrApiCall (threading.Thread): def __init __ (self, sel, chaîne, délai d'attente): self.sel = sel self.original = chaîne self.timeout = délai d'attente self.result = Aucun threading.Thread .__ init __ (auto) def run (self): try: data = urllib.urlencode ('css': self.original) request = urllib2.Request ('http://prefixr.com/api/index.php', data, headers = " User-Agent ":" Préfixe sublime ") http_file = urllib2.urlopen (demande, délai d'attente = self.timeout) self.result = http_file.read () return except (urllib2.HTTPError) comme (e): err = '% s: erreur HTTP% s lorsqu’il a contacté l’API '% (__name__, str (code e.c))) sauf (urllib2.URLError) as (e): err ='% s: erreur d’URL% s lorsqu’il a contacté l’API '% (__name__ e.reason)) sublime.error_message (err) self.result = False
Ici on utilise le fil __init __ ()
méthode pour définir toutes les valeurs nécessaires lors de la requête Web. le courir()
méthode contient le code pour configurer et exécuter la requête HTTP de l’API Prefixr. Comme les threads fonctionnent en même temps que d'autres codes, il n'est pas possible de renvoyer directement des valeurs. Au lieu de cela nous avons mis auto.résultat
au résultat de l'appel.
Depuis que nous avons commencé à utiliser quelques modules supplémentaires dans notre plugin, nous devons les ajouter aux instructions d'importation en haut du script..
importer urllib importer urllib2 importer threading
Maintenant que nous avons une classe threadée pour effectuer les appels HTTP, nous devons créer un thread pour chaque sélection. Pour ce faire, nous retournons dans le courir()
méthode de notre PrefixrCommand
class et utilise la boucle suivante:
threads = [] pour les sélections à venir: string = self.view.substr (sel) thread = PrefixrApiCall (sel, string, 5) threads.append (thread) thread.start ()
Nous gardons une trace de chaque thread que nous créons et appelons ensuite le début()
méthode pour commencer chaque.
Si vous souhaitez vérifier votre travail jusqu'ici, comparez la source au fichier. Prefixr-2.py
dans le fichier zip du code source.
Maintenant que nous avons lancé les demandes de l'API Prefixr, nous devons configurer quelques derniers détails avant de traiter les réponses..
Tout d'abord, nous effaçons toutes les sélections, car nous les avons modifiées plus tôt. Plus tard, nous les rétablirons dans un état raisonnable.
self.view.sel (). clear ()
De plus nous commençons une nouvelle modifier
objet. Cela regroupe les opérations pour annuler et rétablir. Nous spécifions que nous créons un groupe pour le préfixe
commander.
edit = self.view.begin_edit ('prefixr')
Comme dernière étape, nous appelons une méthode que nous écrirons ensuite et qui gérera le résultat des requêtes de l’API..
self.handle_threads (edit, threads, accolades)
À ce stade, nos threads sont en cours d'exécution, voire éventuellement terminés. Ensuite, nous devons mettre en œuvre le handle_threads ()
méthode que nous venons de référencer. Cette méthode va parcourir la liste des threads et rechercher les threads qui ne fonctionnent plus.
def handle_threads (self, edit, threads, accolades, offset = 0, i = 0, dir = 1): next_threads = [] pour le thread dans les threads: if thread.is_alive (): next_threads.append (thread) continue si thread. result == False: continue offset = self.replace (edit, thread, accolades, offset) threads = next_threads
Si un thread est toujours en vie, nous l'ajoutons à la liste des threads à vérifier ultérieurement. Si le résultat est un échec, nous l’ignorons. Cependant, pour obtenir de bons résultats, nous appelons un nouveau remplacer()
méthode que nous écrirons bientôt.
Si des threads sont encore en vie, nous devons les vérifier à nouveau sous peu. En outre, il s'agit d'une amélioration intéressante de l'interface utilisateur consistant à fournir un indicateur d'activité indiquant que notre plug-in est toujours en cours d'exécution..
if len (threads): # Ceci anime un petit indicateur d'activité dans la zone d'état avant = i% 8 after = (7) - avant si pas après: dir = -1 si pas avant: dir = 1 i + = dir self. view.set_status ('prefixr', 'Prefixr [% s =% s]'% \ ("* avant," après)) sublime.set_timeout (lambda: self.handle_threads (edit, threads, accolades, offset, i, dir), 100) retour
La première section de code utilise une valeur entière simple stockée dans la variable je
déplacer un =
et-vient entre deux crochets. La dernière partie est la plus importante cependant. Cela dit à Sublime de lancer le handle_threads ()
méthode à nouveau, avec de nouvelles valeurs, dans 100 millisecondes supplémentaires. C'est comme le setTimeout ()
fonction en JavaScript.
le
lambda
mot clé est une fonctionnalité de Python qui nous permet de créer une nouvelle fonction non nommée ou anonyme..
le sublime.set_timeout ()
La méthode requiert une fonction ou une méthode et le nombre de millisecondes jusqu'à son exécution. Sans pour autant lambda
nous pourrions dire que nous voulions courir handle_threads ()
, mais nous ne serions pas en mesure de spécifier les paramètres.
Si tous les threads sont terminés, nous n'avons pas besoin de définir un autre délai d'expiration, mais nous terminons plutôt notre groupe d'annulation et mettons à jour l'interface utilisateur pour que l'utilisateur sache que tout est terminé..
self.view.end_edit (edit) self.view.erase_status ('prefixr') selections = len (self.view.sel ()) sublime.status_message ('Prefixr a été exécuté avec succès sur% s selection% s'% (selections, " si sélections == 1 autre ')'))
Si vous souhaitez vérifier votre travail jusqu'ici, comparez la source au fichier. Prefixr-3.py
dans le fichier zip du code source.
Avec nos threads gérés, il ne reste plus qu’à écrire le code qui remplace le CSS original par le résultat de l’API Prefixr. Comme nous l’avons mentionné précédemment, nous allons écrire une méthode appelée remplacer()
.
Cette méthode accepte un certain nombre de paramètres, y compris le modifier
object for undo, le thread qui a récupéré le résultat à partir de l'API Prefixr, si la sélection d'origine comprenait des accolades, et enfin le décalage de sélection.
def remplace (self, edit, thread, accolades, offset): sel = thread.sel original = thread.original result = thread.result # Nous ajustons ici chaque sélection pour le texte que nous avons déjà inséré si offset: sel = sublime.Region (sel.begin () + offset, sel.end () + offset)
Le décalage est nécessaire lorsqu'il s'agit de sélections multiples. Lorsque nous remplaçons un bloc de CSS par le CSS préfixé, la longueur de ce bloc augmentera. Le décalage garantit que nous remplaçons le contenu correct pour les sélections ultérieures, car les positions du texte sont décalées à chaque remplacement..
L'étape suivante consiste à préparer le résultat de l'API Prefixr pour qu'il soit ajouté en tant que CSS de remplacement. Cela inclut la conversion des fins de ligne et de l'indentation pour correspondre au document actuel et à la sélection d'origine..
resultat = self.normalize_line_endings (result) (préfixe, principal, suffixe) = self.fix_whitespace (original, result, sel, accolades) self.view.replace (edit, sel, préfixe + principal + suffixe)
Enfin, nous définissons la sélection de l'utilisateur de manière à inclure la fin de la dernière ligne du nouveau CSS que nous avons inséré, puis renvoyons le décalage ajusté à utiliser pour toute sélection ultérieure..
end_point = sel.begin () + len (préfixe) + len (principal) self.view.sel (). add (sublime.Region (point_fin, point_fin)) renvoie l'offset + len (préfixe + principal + suffixe) - len ( original)
Si vous souhaitez vérifier votre travail jusqu'ici, comparez la source au fichier. Prefixr-4.py
dans le fichier zip du code source.
Lors du processus de remplacement, nous avons utilisé deux méthodes personnalisées pour préparer le nouveau CSS pour le document. Ces méthodes prennent le résultat de Prefixr et le modifient pour correspondre au document actuel..
normalize_line_endings ()
prend la chaîne et s'assure qu'elle correspond aux fins de ligne du fichier actuel. Nous utilisons le Réglages
classe de l'API Sublime pour obtenir les fins de ligne appropriées.
def normalize_line_endings (self, chaîne): string = string.replace ('\ r \ n', '\ n'). remplacer ('\ r', '\ n') line_endings = self.view.settings (). get ('default_line_ending') si line_endings == 'windows': string = string.replace ('\ n', '\ r \ n') elif line_endings == 'mac': string = string.replace ('\ n', '\ r') retourne la chaîne
le fix_whitespace ()
La méthode est un peu plus compliquée, mais fait le même type de manipulation, juste pour l'indentation et les espaces dans le bloc CSS. Cette manipulation ne fonctionne vraiment qu'avec un seul bloc de CSS, donc nous quittons si un ou plusieurs accolades étaient inclus dans la sélection d'origine.
def fix_whitespace (self, original, prefixed, sel, accolades): # Si des accolades sont présentes, nous pouvons effectuer toute la magie des blancs si accolades: return (", préfixé,")
Sinon, nous commençons par déterminer le niveau de retrait du CSS original. Ceci est fait en recherchant des espaces au début de la sélection.
(row, col) = self.view.rowcol (sel.begin ()) indent_region = self.view.find ('^ \ s +', self.view.text_point (row, 0)) si self.view.rowcol ( indent_region.begin ()) [0] == ligne: indent = self.view.substr (indent_region) else: indent = "
Ensuite, nous coupons les espaces du CSS préfixé et utilisons les paramètres de vue actuels pour indenter le CSS coupé au niveau original en utilisant des tabulations ou des espaces en fonction des paramètres actuels de l'éditeur..
prefixed = prefixed.strip () prefixed = re.sub (re.compile ('^ \ s +', re.M), ", préfixé) settings = self.view.settings () use_spaces = settings.get ('translate_tabs_to_spaces' ) tab_size = int (settings.get ('tab_size', 8)) indent_characters = '\ t' si use_spaces: indent_characters = "* tab_size prefixed = prefixed.replace ('\ n', '\ n' + indent + indent_characters)
Nous finissons la méthode en utilisant le début et la fin d’espace d'origine pour nous assurer que le nouveau CSS préfixé est exactement identique à l'original..
match = re.search ('^ (\ s *)', original) préfixe = match.groups () [0] match = re.search ('(\ s *) \ Z', original) suffixe = match.groups () [0] retour (préfixe, préfixe, suffixe)
Avec le fix_whitespace ()
méthode, nous avons utilisé le module (re) expression régulière Python, nous devons donc l'ajouter à la liste des importations en haut du script.
import re
Et avec cela, nous avons terminé le processus d'écriture du préfixe
L’étape suivante consiste à rendre la commande facile à exécuter en fournissant un raccourci clavier et une entrée de menu..
La plupart des paramètres et des modifications pouvant être apportés à Sublime sont effectués via des fichiers JSON, et cela est vrai pour les raccourcis clavier. Les liaisons de clés sont généralement spécifiques au système d'exploitation, ce qui signifie que trois fichiers de liaisons de clés devront être créés pour votre plugin. Les fichiers doivent être nommés Par défaut (Windows) .sublime-keymap
, Par défaut (Linux) .sublime-keymap
et Par défaut (OSX) .sublime-keymap
.
Prefixr /… - Par défaut (Linux) .sublime-keymap - Par défaut (OSX) .sublime-keymap - Par défaut (Windows) .sublime-keymap - Prefixr.py
le .sublime-keymap
les fichiers contiennent un tableau JSON contenant des objets JSON pour spécifier les liaisons de clé. Les objets JSON doivent contenir un clés
et commander
clé, et peut également contenir un args
key si la commande nécessite des arguments. Le plus difficile lors du choix d’une liaison de clé est de s’assurer que celle-ci n’est pas déjà utilisée. Cela peut être fait en allant à la Préférences> Liaisons de touches - Par défaut entrée du menu et recherche du raccourci clavier que vous souhaitez utiliser. Une fois que vous avez trouvé une liaison inutilisée, ajoutez-la à votre .sublime-keymap
des dossiers.
["keys": ["ctrl + alt + x"], "command": "prefixr"]
Normalement, les raccourcis clavier Linux et Windows sont les mêmes. La clé cmd sur OS X est spécifiée par la chaîne super
dans le .sublime-keymap
des dossiers. Lors du portage d’une liaison de clé sur plusieurs systèmes d’exploitation, il est courant que ctrl
clé sur Windows et Linux à échanger pour super
sur OS X. Toutefois, il se peut que le mouvement de la main ne soit pas toujours le plus naturel. Si possible, essayez de tester vos combinaisons de touches sur un vrai clavier..
L’un des avantages plus intéressants de l’extension de Sublime est qu’il est possible d’ajouter des éléments à la structure du menu en créant .sublime-menu
des dossiers. Les fichiers de menu doivent porter des noms spécifiques pour indiquer quel menu ils affectent:
Main.sublime-menu
contrôle le menu principal du programmeSide Bar.sublime-menu
contrôle le menu contextuel sur un fichier ou un dossier dans la barre latéraleContext.sublime-menu
contrôle le menu contextuel sur un fichier en cours d'éditionDe nombreux autres fichiers de menu ont une incidence sur divers autres menus de l’interface. En parcourant le Défaut le paquet est le moyen le plus facile de connaître tous ces.
Pour Prefixr, nous voulons ajouter un élément de menu à la modifier menu et quelques entrées au Préférences menu pour les réglages. L’exemple suivant est la structure JSON pour le modifier entrée de menu. J'ai omis les entrées pour le Préférences menu car ils sont assez prolixes étant imbriqués quelques niveaux de profondeur.
["id": "edit", "children": ["id": "wrap", "command": "prefixr"]]
La seule chose à faire attention est le identifiant
clés. En spécifiant le identifiant
d’une entrée de menu existante, il est possible d’ajouter une entrée sans redéfinir la structure existante. Si vous ouvrez le Main.sublime-menu
fichier de la Défaut
package et parcourir, vous pouvez déterminer ce que identifiant
vous voulez ajouter votre entrée à.
À ce stade, votre paquet Prefixr devrait être presque identique à la version officielle sur GitHub.
Maintenant que vous avez pris le temps d'écrire un plugin utile pour Sublime, il est temps de passer aux mains des autres utilisateurs..
Sublime prend en charge la distribution d'un fichier zip d'un répertoire de packages comme moyen simple de partager des packages. Il suffit de compresser votre dossier de paquets et de modifier l’extension en
.sublime-package
. Les autres utilisateurs peuvent maintenant placer ceci dans leur Paquets installés répertoire et redémarrez Sublime pour installer le paquet.
Parallèlement à la disponibilité facile pour de nombreux utilisateurs, la disponibilité de votre package via Package Control garantit aux utilisateurs une mise à niveau automatique vers vos dernières mises à jour..
Bien que cela puisse certainement fonctionner, il existe également un gestionnaire de paquets forSublime appelé Package Control qui prend en charge une liste principale de paquets et de mises à niveau automatiques. Pour que votre paquet soit ajouté au canal par défaut, hébergez-le simplement sur GitHubor BitBucket, puis branchez le fichier de canal (sur GitHub ou BitBucket), ajoutez votre référentiel et envoyez une demande d'extraction. Une fois la demande d'extraction acceptée, votre package sera disponible pour des milliers d'utilisateurs de Sublime. Parallèlement à la disponibilité facile pour de nombreux utilisateurs, la disponibilité de votre package via Package Control garantit aux utilisateurs une mise à niveau automatique vers vos dernières mises à jour..
Si vous ne souhaitez pas héberger sur GitHub ou BitBucket, il existe un système de référentiel / canal JSON personnalisé qui peut être utilisé pour héberger n'importe où, tout en fournissant le package à tous les utilisateurs. Il fournit également des fonctionnalités avancées telles que la spécification de la disponibilité des packages par système d'exploitation. Voir la page PackageControl pour plus de détails.
Maintenant que nous avons parcouru les étapes pour écrire un plugin Sublime, il est temps de plonger! La communauté des plugins Sublime crée et publie de nouvelles fonctionnalités presque tous les jours. Sublime devient de plus en plus puissant et polyvalent à chaque sortie. Le Sublime Text Forum est un endroit idéal pour obtenir de l'aide et discuter avec les autres de ce que vous construisez..