├── .gitignore
├── Default (Linux).sublime-keymap
├── Default (OSX).sublime-keymap
├── Default (Windows).sublime-keymap
├── extract_to_blade.sublime-commands
├── .travis.yml
├── Preferences.sublime-settings
├── appveyor.yml
├── LICENSE
├── extract2blade.py
├── extract_to_blade_command.py
├── README.md
└── tests
└── test.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/*
2 | tests/__pycache__/*
3 |
--------------------------------------------------------------------------------
/Default (Linux).sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | // { "keys": ["super+alt+e"], "command": "extract_to_blade"},
3 | ]
--------------------------------------------------------------------------------
/Default (OSX).sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | // { "keys": ["super+alt+e"], "command": "extract_to_blade"},
3 | ]
--------------------------------------------------------------------------------
/Default (Windows).sublime-keymap:
--------------------------------------------------------------------------------
1 | [
2 | // { "keys": ["ctrl+alt+e"], "command": "extract_to_blade"},
3 | ]
--------------------------------------------------------------------------------
/extract_to_blade.sublime-commands:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "caption": "Extract: Move selection to blade view ...",
4 | "command": "extract_to_blade"
5 | }
6 | ]
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - 3.3
4 | - 3.4
5 | - 3.5
6 | - 3.6
7 | - 3.7-dev
8 |
9 | script:
10 | - python -m unittest tests/test.py
11 |
--------------------------------------------------------------------------------
/Preferences.sublime-settings:
--------------------------------------------------------------------------------
1 | {
2 | "extract_to_blade_save_last_path": true,
3 | "extract_to_blade_relative_path": false,
4 | "extract_to_blade_include_sentence": "@include('%s')"
5 | }
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | environment:
2 |
3 | matrix:
4 | - PYTHON: "C:\\Python33"
5 | - PYTHON: "C:\\Python33-x64"
6 | DISTUTILS_USE_SDK: "1"
7 | - PYTHON: "C:\\Python34"
8 | - PYTHON: "C:\\Python34-x64"
9 | DISTUTILS_USE_SDK: "1"
10 | - PYTHON: "C:\\Python35"
11 | - PYTHON: "C:\\Python35-x64"
12 | - PYTHON: "C:\\Python36"
13 | - PYTHON: "C:\\Python36-x64"
14 |
15 | install:
16 | - "%PYTHON%\\python.exe -m pip install wheel"
17 |
18 | build: off
19 |
20 | test_script:
21 | - "%PYTHON%\\python.exe -m unittest tests/test.py"
22 |
23 | artifacts:
24 | # bdist_wheel puts your built wheel in the dist directory
25 | - path: dist\*
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Mohannad Najjar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/extract2blade.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | class ExtractToBlade(object):
5 | def get_output_directory(path, filename):
6 | filename = filename.replace('.blade.php','')
7 | return ExtractToBlade.output_paths(path, filename)['output_directory']
8 |
9 | def get_absolute_filepath(path, filename):
10 | filename = filename.replace('.blade.php','')
11 | output_paths = ExtractToBlade.output_paths(path, filename)
12 | blade_paths = ExtractToBlade.blade_paths(output_paths['abspath'], filename, output_paths['basename'])
13 | return os.path.join( output_paths['output_directory'] , blade_paths['filename'] )
14 |
15 | def get_blade_filepath(path, filename):
16 | filename = filename.replace('.blade.php','')
17 | output_paths = ExtractToBlade.output_paths(path, filename)
18 | return ExtractToBlade.blade_paths(output_paths['abspath'], filename, output_paths['basename'])['path']
19 |
20 | def get_blade_dirpath(path, filename):
21 | filename = filename.replace('.blade.php','')
22 | output_paths = ExtractToBlade.output_paths(path, filename)
23 | return ExtractToBlade.blade_paths(output_paths['abspath'], filename, output_paths['basename'])['user_dirpath']
24 |
25 | def output_paths(sublime_file_path, filename):
26 | abspath = os.path.normpath(os.path.join(sublime_file_path, filename.strip('//').strip('\\')))
27 |
28 | basename = os.path.basename(abspath)
29 |
30 | if '.' in basename:
31 | abspath = os.path.join( os.path.normpath(abspath.replace(basename,'') ) , basename.replace('.','/'))
32 | basename = os.path.basename(abspath)
33 |
34 |
35 | output_directory = os.path.normpath(os.path.dirname(abspath))
36 |
37 | return {"abspath": abspath, "basename": basename, "output_directory": output_directory}
38 |
39 | def blade_paths(abspath, filename, basename):
40 | blade_path = ExtractToBlade.resolve_blade_path(abspath)
41 | # save how the last time the user entered the path to the blade view
42 | # by ripping off the resolved basename from the input
43 | blade_user_dirpath = ExtractToBlade.rreplace(filename, basename, '',1)
44 |
45 | blade_filename = basename + '.blade.php'
46 |
47 | return {"path": blade_path, "user_dirpath": blade_user_dirpath, "filename": blade_filename}
48 | # replace last occurrence of string https://stackoverflow.com/a/2556156/4330182
49 | def rreplace(s, old, new, count):
50 | return (s[::-1].replace(old[::-1], new[::-1], count))[::-1]
51 |
52 | def blade_views_dir(absolute_path):
53 | absolute_path = absolute_path.lower().replace('\\','/').split('resources/views',1)
54 | path_to_views = absolute_path[0] + 'resources/views/'
55 |
56 | try:
57 | path_after_views = absolute_path[1][1:] # remove first character
58 | except IndexError:
59 | path_after_views = ""
60 |
61 | return { "path_to_views" : path_to_views, "path_after_views" : path_after_views }
62 |
63 | def resolve_blade_path(abspath):
64 | blade_filename = ExtractToBlade.blade_views_dir(abspath)['path_after_views']
65 | blade_filename = blade_filename.replace('/', '.')
66 | return blade_filename
67 |
--------------------------------------------------------------------------------
/extract_to_blade_command.py:
--------------------------------------------------------------------------------
1 | import sublime, sublime_plugin
2 | import os
3 | from time import sleep
4 |
5 | from .extract2blade import ExtractToBlade
6 |
7 | class ExtractToBladeCommand(sublime_plugin.TextCommand):
8 | def run(self, edit):
9 | self.init()
10 |
11 | if not self.allow_relative_path:
12 | self.sublime_file_path = ExtractToBlade.blade_views_dir(self.sublime_file_path)['path_to_views']
13 |
14 | if self.save_last_path:
15 | self.default_blade_input = self.project_data.get('extract2blade_last_blade_path','')
16 |
17 | # If multiple selection, join it by a new line separator
18 | for region in self.view.sel():
19 | if not region.empty():
20 | self.text_selected = self.text_selected + self.view.substr(region) + '\n'
21 |
22 | # Remove last new line formatter
23 | self.text_selected = ExtractToBlade.rreplace(self.text_selected,'\n','',1)
24 |
25 | # Open the new blade file input panel
26 | self.window.show_input_panel(
27 | ('File name (in %s): (suffix: .blade.php)' % (self.sublime_file_path)),
28 | self.default_blade_input, # Default value in input
29 | self.append_to_file, # Method to execute after input
30 | None, # No 'change' handler
31 | self.cancel_handler
32 | )
33 |
34 | # If the feature is enabled, Cancel handler
35 | # will reset the last blade path
36 | def cancel_handler(self):
37 | if self.save_last_path:
38 | self.store_user_dirpath('')
39 |
40 | def append_to_file(self, input_filename):
41 | output_directory = ExtractToBlade.get_output_directory(self.sublime_file_path, input_filename)
42 | absolute_file_path = ExtractToBlade.get_absolute_filepath(self.sublime_file_path, input_filename)
43 | blade_filepath = ExtractToBlade.get_blade_filepath(self.sublime_file_path, input_filename)
44 | blade_dirpath = ExtractToBlade.get_blade_dirpath(self.sublime_file_path, input_filename)
45 |
46 | # Create the directory for the extracted new file if not exist
47 | self.create_dir(output_directory)
48 |
49 | # Add or append the text to the file
50 | self.write_to_file(absolute_file_path, self.text_selected)
51 |
52 | # Remove the original text
53 | self.view.run_command('left_delete')
54 |
55 | # Insert include sentence
56 | self.insert_include_sentence(blade_filepath)
57 |
58 | # Display the file, after appending to it
59 | file_view = self.window.open_file(absolute_file_path)
60 |
61 | # Keep the view open
62 | self.window.focus_view(self.view)
63 |
64 | # If enabled, save how the user entered the path to the file
65 | if self.save_last_path:
66 | self.store_user_dirpath(blade_dirpath)
67 |
68 | def init(self):
69 | self.init_defaults()
70 | self.load_settings()
71 |
72 | def init_defaults(self):
73 | self.window = self.view.window()
74 | self.sublime_vars = self.window.extract_variables()
75 | self.project_data = self.window.project_data()
76 | self.sublime_file_path = self.sublime_vars['file_path']
77 | self.default_blade_input = ''
78 | # extract the text
79 | self.text_selected = ''
80 |
81 | def load_settings(self):
82 | sublime_preferences = sublime.load_settings('Preferences.sublime-settings')
83 | self.save_last_path = sublime_preferences.get('extract_to_blade_save_last_path', True)
84 | self.allow_relative_path = sublime_preferences.get('extract_to_blade_relative_path', False)
85 | self.include_sentence = sublime_preferences.get('extract_to_blade_include_sentence', "@include('%s')")
86 |
87 | def create_dir(self, directory):
88 | if not os.path.exists(directory):
89 | os.makedirs(directory)
90 |
91 | def write_to_file(self, absolute_file_path, text):
92 | f = open(absolute_file_path, 'a', encoding="utf-8")
93 | f.write(text)
94 | f.close()
95 |
96 | def store_user_dirpath(self, user_dirpath):
97 | proj_data = self.project_data
98 | proj_data['extract2blade_last_blade_path'] = user_dirpath
99 | self.window.set_project_data(proj_data)
100 |
101 | def insert_include_sentence(command_instance, blade_path):
102 | include_sentence = (command_instance.include_sentence % (blade_path))
103 |
104 | # Create the blade "include" sentence
105 | command_instance.view.run_command('insert', {"characters": include_sentence })
106 |
107 | # Hide Autocomplete
108 | command_instance.view.run_command('insert', {"characters": '\n'})
109 | command_instance.view.run_command("hide_auto_complete")
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Extract Text to Laravel Blade View
2 |
3 | [](https://travis-ci.org/MohannadNaj/sublime-extract-to-blade) [](https://ci.appveyor.com/project/MohannadNaj/sublime-extract-to-blade)
4 |
5 |
6 | This plugin for Sublime Text 3 allows you to extract the selected text into a new or existing [laravel blade views](https://laravel.com/docs/master/blade) with the `@include` sentence and the appropriate path.
7 |
8 | 
9 |
10 | ## 💾 Installation
11 |
12 | ### Package Control
13 |
14 | It is highly recommended to install `Extract Text to Laravel Blade View` with [Package Control](https://packagecontrol.io).
15 |
16 | 1. [Install Package Control](https://packagecontrol.io/installation) if you haven't yet.
17 | 2. Open the command palette (Ctrl+Shift+P for Windows/Linux, Cmd+Shift+P for Mac OS)
18 | 3. Search for _Package Control: Install Package_ and hit Enter.
19 | 4. Type `Extract Text to Laravel Blade View` and press Enter to install it.
20 |
21 |
22 | ### Manual Installation
23 |
24 | You can clone this repository into your _Sublime Text 3/Packages_
25 |
26 | ```shell
27 | git clone https://github.com/MohannadNaj/sublime-extract-to-blade
28 | ```
29 |
30 | ##### Mac OS
31 |
32 | ```shell
33 | cd ~/Library/Application Support/Sublime Text 3/Packages/
34 | git clone git://github.com/MohannadNaj/sublime-extract-to-blade.git
35 | ```
36 |
37 |
38 | ##### Linux
39 |
40 | ```shell
41 | cd ~/.config/sublime-text-3/Packages
42 | git clone git://github.com/MohannadNaj/sublime-extract-to-blade.git
43 | ```
44 |
45 |
46 | ##### Windows
47 |
48 | ```shell
49 | cd "%APPDATA%\Sublime Text 3\Packages"
50 | git clone git://github.com/MohannadNaj/sublime-extract-to-blade.git
51 | ```
52 |
53 | 👉 The `git` command must be available on the command line.
54 |
55 | 👉 You may need to add the directory containing `git.exe` to your `PATH` environment variable.
56 |
57 |
58 | ## Usage
59 |
60 | - While on a Laravel Blade View, Select some text
61 | - open the Command Palette (Ctrl+Shift+P for Windows/Linux, Cmd+Shift+P for Mac OS), and look for "Extract: Move selection to blade view ..".
62 | > Alternatively, you can set a key map for this step. see [Keymap](#keymap)
63 |
64 | - Enter the blade path for the new blade view (e.g: `welcome.services`)
65 | > you can use relative blade paths also if it's enabled. see [Options](#options)
66 |
67 | The plugin will create or append the extracted text to the newly created blade view, and insert `@include` statement in the text source file. The plugin will look for the `resources/views/` directory to resolve the entered path.
68 |
69 | ## Options
70 | Set your options by navigating to _Preferences > Settings_.
71 |
72 | ### extract_to_blade_save_last_path
73 | _default: true_
74 | ``` js
75 | {
76 | "extract_to_blade_save_last_path": true
77 | }
78 | ```
79 | By enabling this option, the plugin will remember how you located the directory of the blade file the last time you extracted text, and will set the next input to the same directory.
80 |
81 | If you extracted a portion of the text to `welcome.about`, the next time the input will be ready for you by default: `welcome.`.
82 |
83 | ### extract_to_blade_relative_path
84 | _default: false_
85 | ``` js
86 | {
87 | "extract_to_blade_relative_path": false
88 | }
89 | ```
90 | By enabling this option, the plugin will build the blade paths relatively to the text source file path.
91 |
92 | If you extracted text from `resources/views/layouts/app.blade.php` and typed: `header`, it will create the file on `resources/views/layouts/`, so the blade path for it will be: `@include('layouts.header')`.
93 |
94 | Disable this if you used to write the full blade path at your `include` statements.
95 |
96 |
97 | ### extract_to_blade_include_sentence
98 | _default: @include('%s')_
99 | ``` js
100 | {
101 | "extract_to_blade_include_sentence": "@include('%s')"
102 | }
103 | ```
104 | The sentence will be used for entering the resolved blade path.
105 |
106 | Change this if you prefer the double quotes over the apostrophe for example.
107 | ``` js
108 | {
109 | // double quotes + 4 lines after!!
110 | "extract_to_blade_include_sentence": "@include(\"%s\")\n\n\n\n"
111 | }
112 | ```
113 |
114 | ## Keymap
115 |
116 | You can set the keymap for extracting the selected text to a Laravel blade view from _Preferences > Key Bindings_. Assuming you want Ctrl+Alt+E as the command shortcut:
117 | ``` js
118 | [
119 | // windows
120 | { "keys": ["ctrl+alt+e"], "command": "extract_to_blade"},
121 |
122 | // Linux and Mac OS
123 | { "keys": ["super+alt+e"], "command": "extract_to_blade"},
124 | ]
125 | ```
126 |
127 | ## Credits
128 |
129 | - The forked [Extract Text to File](https://github.com/dreki/sublime-extract-to-file) plugin
130 | - The [Installation](#installation) part on this README was modified from [GitGutter's README file](https://github.com/jisaacks/GitGutter/blob/master/README.md)
131 |
--------------------------------------------------------------------------------
/tests/test.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append('../')
3 |
4 | from extract2blade import ExtractToBlade
5 |
6 | import unittest
7 | import os
8 | # https://stackoverflow.com/a/652299/4330182
9 | class Test(object):
10 | def __new__(cls, **attrs):
11 | result = object.__new__(cls)
12 | result.__dict__ = attrs
13 | return result
14 |
15 | class TestPathsMethods(unittest.TestCase):
16 | def test_1(self):
17 | tests = [
18 | Test(
19 | input="welcome",
20 | path=os.path.normpath('/path/to/resources/views/'),
21 | output_directory=os.path.normpath('/path/to/resources/views/'),
22 | absolute_filepath=os.path.normpath('/path/to/resources/views/welcome.blade.php'),
23 | blade_filepath="welcome",
24 | blade_dirpath="",
25 | ),
26 | Test(
27 | input="wel/foo/bar",
28 | path=os.path.normpath('/path/to/resources/views/'),
29 | output_directory=os.path.normpath('/path/to/resources/views/wel/foo'),
30 | absolute_filepath=os.path.normpath('/path/to/resources/views/wel/foo/bar.blade.php'),
31 | blade_filepath="wel.foo.bar",
32 | blade_dirpath="wel/foo/",
33 | ),
34 | Test(
35 | input="wel.foo.bar",
36 | path=os.path.normpath('/path/to/resources/views/'),
37 | output_directory=os.path.normpath('/path/to/resources/views/wel/foo'),
38 | absolute_filepath=os.path.normpath('/path/to/resources/views/wel/foo/bar.blade.php'),
39 | blade_filepath="wel.foo.bar",
40 | blade_dirpath="wel.foo.",
41 | ),
42 | Test(
43 | input="wel/FOo.bar",
44 | path=os.path.normpath('/path/to/aresources/viewS/'),
45 | output_directory=os.path.normpath('/path/to/aresources/viewS/wel/FOo'),
46 | absolute_filepath=os.path.normpath('/path/to/aresources/viewS/wel/FOo/bar.blade.php'),
47 | blade_filepath="wel.foo.bar",
48 | blade_dirpath="wel/FOo.",
49 | ),
50 | Test(
51 | input="/moh/FOo.bar",
52 | path=os.path.normpath('/path/to/aresources/viewS/'),
53 | output_directory=os.path.normpath('/path/to/aresources/viewS/moh/FOo'),
54 | absolute_filepath=os.path.normpath('/path/to/aresources/viewS/moh/FOo/bar.blade.php'),
55 | blade_filepath="moh.foo.bar",
56 | blade_dirpath="/moh/FOo.",
57 | ),
58 | Test(
59 | input="\\hello/foo.bar",
60 | path=os.path.normpath('/path/to/aresources/viewS/'),
61 | output_directory=os.path.normpath('/path/to/aresources/viewS/hello/foo'),
62 | absolute_filepath=os.path.normpath('/path/to/aresources/viewS/hello/foo/bar.blade.php'),
63 | blade_filepath="hello.foo.bar",
64 | blade_dirpath="\\hello/foo.",
65 | ),
66 | Test(
67 | input="../hello/foo.bar",
68 | path=os.path.normpath('/path/to/resources/views/relative/'),
69 | output_directory=os.path.normpath('/path/to/resources/views/hello/foo'),
70 | absolute_filepath=os.path.normpath('/path/to/resources/views/hello/foo/bar.blade.php'),
71 | blade_filepath="hello.foo.bar",
72 | blade_dirpath="../hello/foo.",
73 | ),
74 | Test(
75 | input="hello/foo.bar.hi",
76 | path=os.path.normpath('/path/to/resources/views/'),
77 | output_directory=os.path.normpath('/path/to/resources/views/hello/foo/bar'),
78 | absolute_filepath=os.path.normpath('/path/to/resources/views/hello/foo/bar/hi.blade.php'),
79 | blade_filepath="hello.foo.bar.hi",
80 | blade_dirpath="hello/foo.bar.",
81 | ),
82 | Test(
83 | input="../../welcome.modal",
84 | path=os.path.normpath('/path/to/resources/views/shared/layouts'),
85 | output_directory=os.path.normpath('/path/to/resources/views/welcome'),
86 | absolute_filepath=os.path.normpath('/path/to/resources/views/welcome/modal.blade.php'),
87 | blade_filepath="welcome.modal",
88 | blade_dirpath="../../welcome.",
89 | ),
90 | Test(
91 | input="../../welcome.partials.modal",
92 | path=os.path.normpath('/path/to/resources/views/shared/layouts'),
93 | output_directory=os.path.normpath('/path/to/resources/views/welcome/partials'),
94 | absolute_filepath=os.path.normpath('/path/to/resources/views/welcome/partials/modal.blade.php'),
95 | blade_filepath="welcome.partials.modal",
96 | blade_dirpath="../../welcome.partials.",
97 | ),
98 | Test(
99 | input="header",
100 | path=os.path.normpath('/path/to/resources/views/layouts/'),
101 | output_directory=os.path.normpath('/path/to/resources/views/layouts'),
102 | absolute_filepath=os.path.normpath('/path/to/resources/views/layouts/header.blade.php'),
103 | blade_filepath="layouts.header",
104 | blade_dirpath="",
105 | ),
106 | Test(
107 | input="../header",
108 | path=os.path.normpath('/path/to/resources/_views/layouts/'),
109 | output_directory=os.path.normpath('/path/to/resources/_views/'),
110 | absolute_filepath=os.path.normpath('/path/to/resources/_views/header.blade.php'),
111 | blade_filepath="", # Can't resolve blade path!
112 | blade_dirpath="../",
113 | ),
114 | ]
115 |
116 | for test in tests:
117 | output_directory = ExtractToBlade.get_output_directory(test.path, test.input)
118 | absolute_filepath = ExtractToBlade.get_absolute_filepath(test.path, test.input)
119 | blade_filepath = ExtractToBlade.get_blade_filepath(test.path, test.input)
120 | blade_dirpath = ExtractToBlade.get_blade_dirpath(test.path, test.input)
121 | if not test.output_directory == False:
122 | self.assertEqual(output_directory, test.output_directory)
123 | if not test.absolute_filepath == False:
124 | self.assertEqual(absolute_filepath, test.absolute_filepath)
125 | if not test.blade_filepath == False:
126 | self.assertEqual(blade_filepath, test.blade_filepath)
127 | if not test.blade_dirpath == False:
128 | self.assertEqual(blade_dirpath, test.blade_dirpath)
129 |
--------------------------------------------------------------------------------