├── .editorconfig
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ └── BUG-Report.yml
└── workflows
│ └── ci.yml
├── Documentation
├── Changelog.md
├── Contribute.md
├── Customize.md
├── Keybindings.md
└── Settings.md
├── LICENSE
├── README.md
├── Resources
├── Keymap.json
├── Menus.json
├── Screenshots
│ └── Preview.gif
└── Stylesheet.less
├── Source
├── App.js
├── errors
│ └── early-termination-signal.js
├── scroll-markers
│ └── scroll-markers-service.js
├── search-model.js
├── selection-manager.js
├── status-bar
│ ├── status-bar-service.js
│ └── status-bar-view.js
└── utils
│ ├── editor-finders.js
│ ├── escape-reg-exp.js
│ ├── is-word-selected.js
│ └── non-word-characters.js
├── Tests
├── fixtures
│ ├── hex.md
│ ├── sample.coffee
│ └── sample.php
├── highlight-selected-spec.js
├── main-spec.js
├── scroll-markers
│ └── scroll-markers-service-spec.js
├── status-bar
│ ├── status-bar-service-spec.js
│ └── status-bar-view-spec.js
└── utils
│ └── non-word-characters-spec.js
└── package.json
/.editorconfig:
--------------------------------------------------------------------------------
1 |
2 | root = true
3 |
4 | [*]
5 |
6 | end_of_line = lf
7 |
8 | [*.{gitignore,json,less,yml,js,md}]
9 |
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | indent_style = space
13 | indent_size = 4
14 | charset = utf-8
15 |
16 | [*.md]
17 |
18 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 |
2 | custom : [ 'https://monzo.me/richrace/3.00?d=For%20a%20coffee,%20thanks%20for%20Highlight%20Selected!%20%F0%9F%8E%89%20%E2%98%95%EF%B8%8F' ]
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG-Report.yml:
--------------------------------------------------------------------------------
1 |
2 | description : Create a new ticket for a bug.
3 | title : ❌ Title
4 | name : Bug Report
5 |
6 | labels:
7 |
8 | - bug
9 |
10 | body:
11 |
12 | # Pulsar Version
13 |
14 | - type : textarea
15 | id : pulsar-version
16 |
17 | attributes:
18 |
19 | description : Version of Pulsar, check with `pulsar --version`
20 | label : Pulsar Version
21 | value : |
22 | Pulsar : 1.100.0-beta
23 | Electron : 12.2.3
24 | Chrome : 89.0.4389.128
25 | Node : 14.16.0
26 |
27 | validations:
28 |
29 | required : true
30 |
31 |
32 | # Package Version
33 |
34 | - type : input
35 | id : package-version
36 |
37 | attributes:
38 |
39 | description : Version of Highlight-Line.
40 | placeholder : 0.12.0
41 | label : Package Version
42 |
43 | validations:
44 |
45 | required : true
46 |
47 |
48 | # Description
49 |
50 | - type : textarea
51 | id : description
52 |
53 | attributes:
54 |
55 | description : Please describe your problem as detailed as possible.
56 | label : Description
57 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 |
2 | name: CI
3 |
4 | # Disabled as long as the GitHub Action
5 | # is not available / ppm is not properly
6 | # installed.
7 | #
8 | on:
9 | workflow_dispatch:
10 |
11 | # pull_request:
12 |
13 | # push:
14 | # branches:
15 |
16 | # - main
17 |
18 | jobs:
19 |
20 | Test:
21 |
22 | runs-on : ${{ matrix.os }}
23 | if : "!contains(github.event.head_commit.message,'[skip ci]')"
24 |
25 | strategy:
26 | matrix:
27 | channel : [ stable , beta ]
28 | os : [ ubuntu-latest , macos-latest , windows-latest ]
29 |
30 | steps:
31 |
32 | - uses : actions/checkout@v3
33 |
34 | # - uses : pulsar-edit/action-setup-pulsar
35 | # with :
36 | # channel : ${{ matrix.channel }}
37 |
38 | - name : Print Pulsar's Version
39 | run : pulsar -v
40 |
41 | - name : Print PPM's Version
42 | run : ppm -v
43 |
44 | - name : Install Dependencies
45 | run : ppm ci
46 | env :
47 | APM_TEST_PACKAGES : minimap minimap-highlight-selected status-bar
48 |
49 | - name : Run Tests
50 | run : npm run test
51 |
52 |
53 | Skip:
54 |
55 | runs-on : ubuntu-latest
56 | if : "contains(github.event.head_commit.message,'[skip ci]')"
57 |
58 | steps:
59 |
60 | - name : Skip CI 🚫
61 | run : echo skip ci
62 |
--------------------------------------------------------------------------------
/Documentation/Changelog.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [v0.17.0](https://github.com/richrace/highlight-selected/tree/v0.17.0) (2020-01-14)
4 |
5 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.16.0...v0.17.0)
6 |
7 | **Fixed bugs:**
8 |
9 | - Highlight fails on neighbouring words [\#201](https://github.com/richrace/highlight-selected/issues/201)
10 |
11 | **Closed issues:**
12 |
13 | - Uncaught Error: regular expression is too large [\#206](https://github.com/richrace/highlight-selected/issues/206)
14 | - Change Text color of selected word [\#98](https://github.com/richrace/highlight-selected/issues/98)
15 |
16 | **Merged pull requests:**
17 |
18 | - Use GitHub actions [\#211](https://github.com/richrace/highlight-selected/pull/211) ([richrace](https://github.com/richrace))
19 | - Correctly handle huge selection. [\#210](https://github.com/richrace/highlight-selected/pull/210) ([elarivie](https://github.com/elarivie))
20 | - Bump eslint-utils from 1.3.1 to 1.4.2 [\#205](https://github.com/richrace/highlight-selected/pull/205) ([dependabot[bot]](https://github.com/apps/dependabot))
21 | - Bump lodash from 4.17.11 to 4.17.14 [\#204](https://github.com/richrace/highlight-selected/pull/204) ([dependabot[bot]](https://github.com/apps/dependabot))
22 | - 201 fix regex [\#202](https://github.com/richrace/highlight-selected/pull/202) ([richrace](https://github.com/richrace))
23 | - Bump js-yaml from 3.12.1 to 3.13.1 [\#200](https://github.com/richrace/highlight-selected/pull/200) ([dependabot[bot]](https://github.com/apps/dependabot))
24 |
25 | ## [v0.16.0](https://github.com/richrace/highlight-selected/tree/v0.16.0) (2019-03-24)
26 |
27 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.15.0...v0.16.0)
28 |
29 | **Closed issues:**
30 |
31 | - Rewrite to JS [\#175](https://github.com/richrace/highlight-selected/issues/175)
32 |
33 | **Merged pull requests:**
34 |
35 | - Rewrite to ES6 [\#196](https://github.com/richrace/highlight-selected/pull/196) ([richrace](https://github.com/richrace))
36 |
37 | ## [v0.15.0](https://github.com/richrace/highlight-selected/tree/v0.15.0) (2019-03-17)
38 |
39 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.14.0...v0.15.0)
40 |
41 | **Fixed bugs:**
42 |
43 | - Selected tab and space [\#182](https://github.com/richrace/highlight-selected/issues/182)
44 |
45 | **Closed issues:**
46 |
47 | - Use Grammar Non Word Characters [\#183](https://github.com/richrace/highlight-selected/issues/183)
48 |
49 | **Merged pull requests:**
50 |
51 | - Limit the maximum number of highlight markers [\#193](https://github.com/richrace/highlight-selected/pull/193) ([wbinnssmith](https://github.com/wbinnssmith))
52 | - Block only whitespace selections [\#190](https://github.com/richrace/highlight-selected/pull/190) ([Arcanemagus](https://github.com/Arcanemagus))
53 | - Use the grammar's definition of nonWordCharacters [\#189](https://github.com/richrace/highlight-selected/pull/189) ([Arcanemagus](https://github.com/Arcanemagus))
54 |
55 | ## [v0.14.0](https://github.com/richrace/highlight-selected/tree/v0.14.0) (2018-07-08)
56 |
57 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.13.1...v0.14.0)
58 |
59 | **Implemented enhancements:**
60 |
61 | - Integrate with scroll-marker to highlight matches on the scrollbar [\#173](https://github.com/richrace/highlight-selected/issues/173)
62 | - Doesn't work for unicode words [\#105](https://github.com/richrace/highlight-selected/issues/105)
63 | - Support for same file in multiple panes [\#82](https://github.com/richrace/highlight-selected/issues/82)
64 |
65 | **Fixed bugs:**
66 |
67 | - Uncaught TypeError: Cannot read property 'visibleMarkerLayer' of undefined [\#179](https://github.com/richrace/highlight-selected/issues/179)
68 | - Split pane issues [\#178](https://github.com/richrace/highlight-selected/issues/178)
69 |
70 | **Closed issues:**
71 |
72 | - Update Readme [\#176](https://github.com/richrace/highlight-selected/issues/176)
73 | - Option to highlight one-letter variables [\#170](https://github.com/richrace/highlight-selected/issues/170)
74 | - Uncaught Error: PCRE does not support \L, \l, \N{name}, \U, or \u [\#169](https://github.com/richrace/highlight-selected/issues/169)
75 | - Uncaught Error: PCRE does not support /L, \l, \N{name}, \U, or \u [\#168](https://github.com/richrace/highlight-selected/issues/168)
76 | - Change text when highlighted [\#160](https://github.com/richrace/highlight-selected/issues/160)
77 | - Cyrillic letters [\#157](https://github.com/richrace/highlight-selected/issues/157)
78 | - feature: show highlights in scrollbar [\#155](https://github.com/richrace/highlight-selected/issues/155)
79 | - Chinese character cannot be highlighted [\#153](https://github.com/richrace/highlight-selected/issues/153)
80 | - Uncaught TypeError: escapeRegExp is not a function [\#152](https://github.com/richrace/highlight-selected/issues/152)
81 | - Highlight Background Only on Selected Words [\#151](https://github.com/richrace/highlight-selected/issues/151)
82 | - HighlightedAreaView.onDidAddSelectedMarker is deprecated. [\#149](https://github.com/richrace/highlight-selected/issues/149)
83 | - HighlightedAreaView.onDidAddMarker is deprecated. [\#147](https://github.com/richrace/highlight-selected/issues/147)
84 | - Selection not highlighted when hardware acceleration is disabled [\#146](https://github.com/richrace/highlight-selected/issues/146)
85 | - Whole Words option should support the "$" symbol for JS files [\#141](https://github.com/richrace/highlight-selected/issues/141)
86 | - $variables cannot be highlighted [\#132](https://github.com/richrace/highlight-selected/issues/132)
87 | - Word-boundaries not in line with language settings [\#117](https://github.com/richrace/highlight-selected/issues/117)
88 | - Highlight any selection \(without double-clicking\) [\#113](https://github.com/richrace/highlight-selected/issues/113)
89 | - Missing highlight when line is folded [\#108](https://github.com/richrace/highlight-selected/issues/108)
90 | - Need to highlight variable names starting with $ in Perl as well [\#107](https://github.com/richrace/highlight-selected/issues/107)
91 | - Hightlight status bar shows incorrect num of matches [\#103](https://github.com/richrace/highlight-selected/issues/103)
92 | - Can't select non latin symbols [\#102](https://github.com/richrace/highlight-selected/issues/102)
93 | - Feature Request: Create Cursors On Marked Areas [\#99](https://github.com/richrace/highlight-selected/issues/99)
94 | - Feature request: PHP $ 'special case' should be an option [\#88](https://github.com/richrace/highlight-selected/issues/88)
95 |
96 | **Merged pull requests:**
97 |
98 | - add command to select all markers [\#164](https://github.com/richrace/highlight-selected/pull/164) ([econtal](https://github.com/econtal))
99 | - Add configuration to adjust the string in the status bar [\#163](https://github.com/richrace/highlight-selected/pull/163) ([fuelingtheweb](https://github.com/fuelingtheweb))
100 | - Add special case for Perl `$` `%` and `@` variables [\#162](https://github.com/richrace/highlight-selected/pull/162) ([Wigginns](https://github.com/Wigginns))
101 | - Allow highlighting across word boundaries [\#154](https://github.com/richrace/highlight-selected/pull/154) ([ion201](https://github.com/ion201))
102 |
103 | ## [v0.13.1](https://github.com/richrace/highlight-selected/tree/v0.13.1) (2017-03-24)
104 |
105 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.13.0...v0.13.1)
106 |
107 | **Closed issues:**
108 |
109 | - Deprecation Notice [\#145](https://github.com/richrace/highlight-selected/issues/145)
110 | - Uncaught TypeError: Cannot read property 'scanInBufferRange' of undefined [\#127](https://github.com/richrace/highlight-selected/issues/127)
111 |
112 | **Merged pull requests:**
113 |
114 | - Optimize load time [\#148](https://github.com/richrace/highlight-selected/pull/148) ([zertosh](https://github.com/zertosh))
115 |
116 | ## [v0.13.0](https://github.com/richrace/highlight-selected/tree/v0.13.0) (2017-03-23)
117 |
118 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.12.0...v0.13.0)
119 |
120 | **Closed issues:**
121 |
122 | - Failed to activate the highlight-selected package [\#142](https://github.com/richrace/highlight-selected/issues/142)
123 | - Uncaught TypeError: Cannot read property 'push' of undefined [\#140](https://github.com/richrace/highlight-selected/issues/140)
124 | - Deprecated selector in `highlight-selected\styles\highlight-selected.less` [\#134](https://github.com/richrace/highlight-selected/issues/134)
125 | - Deprecated selector in `highlight-selected/styles/highlight-selected.less` [\#131](https://github.com/richrace/highlight-selected/issues/131)
126 |
127 | **Merged pull requests:**
128 |
129 | - Add HACK grammar to $ special handling [\#143](https://github.com/richrace/highlight-selected/pull/143) ([zertosh](https://github.com/zertosh))
130 | - Add a Gitter chat badge to README.md [\#86](https://github.com/richrace/highlight-selected/pull/86) ([gitter-badger](https://github.com/gitter-badger))
131 |
132 | ## [v0.12.0](https://github.com/richrace/highlight-selected/tree/v0.12.0) (2017-01-11)
133 |
134 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.11.2...v0.12.0)
135 |
136 | **Closed issues:**
137 |
138 | - Deprecation warnings in Atom 1.13.0 [\#138](https://github.com/richrace/highlight-selected/issues/138)
139 | - Can't change selection "shading" color, only the border color [\#137](https://github.com/richrace/highlight-selected/issues/137)
140 | - Feature request: Highlight selected word on mini-map [\#135](https://github.com/richrace/highlight-selected/issues/135)
141 | - if the view is splict to left and right, possible to highlight right when click left [\#123](https://github.com/richrace/highlight-selected/issues/123)
142 | - Uncaught TypeError: Failed to execute 'item' on 'HTMLCollection': 1 argument required, but only 0 present. [\#122](https://github.com/richrace/highlight-selected/issues/122)
143 | - Crashes when pointer position is changed [\#121](https://github.com/richrace/highlight-selected/issues/121)
144 | - High startup time [\#118](https://github.com/richrace/highlight-selected/issues/118)
145 | - \[Suggestion\] Match only whole word [\#116](https://github.com/richrace/highlight-selected/issues/116)
146 | - Mouse button release not being detected [\#114](https://github.com/richrace/highlight-selected/issues/114)
147 | - Performance on large files [\#104](https://github.com/richrace/highlight-selected/issues/104)
148 | - Highlight only when match found [\#90](https://github.com/richrace/highlight-selected/issues/90)
149 | - How to add a keybinding to highlight the word under the cursor? [\#87](https://github.com/richrace/highlight-selected/issues/87)
150 | - Failed to activate the remember-session package [\#55](https://github.com/richrace/highlight-selected/issues/55)
151 |
152 | **Merged pull requests:**
153 |
154 | - Retire :host and ::shadow pseudo-selectors [\#136](https://github.com/richrace/highlight-selected/pull/136) ([pyrotechnick](https://github.com/pyrotechnick))
155 | - Switches to Marker Layers API [\#128](https://github.com/richrace/highlight-selected/pull/128) ([dbachko](https://github.com/dbachko))
156 | - Highlight selection across active panes [\#126](https://github.com/richrace/highlight-selected/pull/126) ([mswiszcz](https://github.com/mswiszcz))
157 |
158 | ## [v0.11.2](https://github.com/richrace/highlight-selected/tree/v0.11.2) (2016-02-02)
159 |
160 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.11.1...v0.11.2)
161 |
162 | **Closed issues:**
163 |
164 | - High CPU usage [\#110](https://github.com/richrace/highlight-selected/issues/110)
165 | - Highlight Line Numbers also when selected \( enhancement \) [\#76](https://github.com/richrace/highlight-selected/issues/76)
166 |
167 | **Merged pull requests:**
168 |
169 | - Added inline-block class for better compatibility [\#106](https://github.com/richrace/highlight-selected/pull/106) ([scippio](https://github.com/scippio))
170 |
171 | ## [v0.11.1](https://github.com/richrace/highlight-selected/tree/v0.11.1) (2015-11-15)
172 |
173 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.11.0...v0.11.1)
174 |
175 | ## [v0.11.0](https://github.com/richrace/highlight-selected/tree/v0.11.0) (2015-11-15)
176 |
177 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.10.1...v0.11.0)
178 |
179 | **Implemented enhancements:**
180 |
181 | - Counter for highlighted words [\#94](https://github.com/richrace/highlight-selected/issues/94)
182 | - Command to toggle highlight selected [\#92](https://github.com/richrace/highlight-selected/issues/92)
183 | - Add API [\#63](https://github.com/richrace/highlight-selected/issues/63)
184 |
185 | **Closed issues:**
186 |
187 | - Plugin should only select fully matching items [\#101](https://github.com/richrace/highlight-selected/issues/101)
188 | - Don't highlight partial matches [\#95](https://github.com/richrace/highlight-selected/issues/95)
189 | - Status bar number of highlight/occurrences is one off [\#93](https://github.com/richrace/highlight-selected/issues/93)
190 | - I cannot install this package [\#91](https://github.com/richrace/highlight-selected/issues/91)
191 | - Only highlight occurences in lines below/above selected word [\#89](https://github.com/richrace/highlight-selected/issues/89)
192 | - Uncaught TypeError: Cannot read property 'dispose' of undefined [\#85](https://github.com/richrace/highlight-selected/issues/85)
193 |
194 | **Merged pull requests:**
195 |
196 | - Add Highlighted info to the status bar. Closes \#94 [\#100](https://github.com/richrace/highlight-selected/pull/100) ([richrace](https://github.com/richrace))
197 | - Add basic API [\#81](https://github.com/richrace/highlight-selected/pull/81) ([richrace](https://github.com/richrace))
198 |
199 | ## [v0.10.1](https://github.com/richrace/highlight-selected/tree/v0.10.1) (2015-06-17)
200 |
201 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.10.0...v0.10.1)
202 |
203 | **Fixed bugs:**
204 |
205 | - Not closing the bottom/top of the highlight on line 144/145 [\#84](https://github.com/richrace/highlight-selected/issues/84)
206 |
207 | **Closed issues:**
208 |
209 | - Highlight with one click [\#83](https://github.com/richrace/highlight-selected/issues/83)
210 |
211 | ## [v0.10.0](https://github.com/richrace/highlight-selected/tree/v0.10.0) (2015-06-14)
212 |
213 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.9.3...v0.10.0)
214 |
215 | **Implemented enhancements:**
216 |
217 | - Only highlight after timeout [\#75](https://github.com/richrace/highlight-selected/issues/75)
218 |
219 | **Closed issues:**
220 |
221 | - Highlight not always working with double click to select word [\#77](https://github.com/richrace/highlight-selected/issues/77)
222 | - Can not use cmd key to multi-select content [\#74](https://github.com/richrace/highlight-selected/issues/74)
223 | - Whole Words option should support the "$" symbol for PHP files [\#73](https://github.com/richrace/highlight-selected/issues/73)
224 | - can't see which ones are selected [\#71](https://github.com/richrace/highlight-selected/issues/71)
225 | - An error message shows up with no obvious abnormal behavior [\#70](https://github.com/richrace/highlight-selected/issues/70)
226 | - Uncaught TypeError: Cannot read property 'dispose' of undefined [\#69](https://github.com/richrace/highlight-selected/issues/69)
227 |
228 | **Merged pull requests:**
229 |
230 | - Add special case for PHP `$` variables [\#80](https://github.com/richrace/highlight-selected/pull/80) ([richrace](https://github.com/richrace))
231 | - Add debounce feature [\#79](https://github.com/richrace/highlight-selected/pull/79) ([richrace](https://github.com/richrace))
232 |
233 | ## [v0.9.3](https://github.com/richrace/highlight-selected/tree/v0.9.3) (2015-05-15)
234 |
235 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.9.2...v0.9.3)
236 |
237 | **Closed issues:**
238 |
239 | - Uncaught TypeError: Cannot read property 'dispose' of undefined [\#67](https://github.com/richrace/highlight-selected/issues/67)
240 | - Failed to load the highlight-selected package [\#65](https://github.com/richrace/highlight-selected/issues/65)
241 | - Uncaught TypeError: undefined is not a function [\#61](https://github.com/richrace/highlight-selected/issues/61)
242 |
243 | **Merged pull requests:**
244 |
245 | - Remove dependency on 'atom-space-pen-views' [\#78](https://github.com/richrace/highlight-selected/pull/78) ([jccr](https://github.com/jccr))
246 | - fix \#67 [\#68](https://github.com/richrace/highlight-selected/pull/68) ([yongkangchen](https://github.com/yongkangchen))
247 | - Update README.md [\#66](https://github.com/richrace/highlight-selected/pull/66) ([simon-clay](https://github.com/simon-clay))
248 | - Test minimap dependencies [\#62](https://github.com/richrace/highlight-selected/pull/62) ([richrace](https://github.com/richrace))
249 |
250 | ## [v0.9.2](https://github.com/richrace/highlight-selected/tree/v0.9.2) (2015-04-18)
251 |
252 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.9.1...v0.9.2)
253 |
254 | **Fixed bugs:**
255 |
256 | - Hide highlight on multiselect [\#56](https://github.com/richrace/highlight-selected/issues/56)
257 |
258 | **Closed issues:**
259 |
260 | - Only highlight matches when they are whole words [\#59](https://github.com/richrace/highlight-selected/issues/59)
261 | - Module fails to activate [\#52](https://github.com/richrace/highlight-selected/issues/52)
262 |
263 | **Merged pull requests:**
264 |
265 | - Fix \#56 [\#58](https://github.com/richrace/highlight-selected/pull/58) ([hmatsuda](https://github.com/hmatsuda))
266 | - update link reference [\#57](https://github.com/richrace/highlight-selected/pull/57) ([nobitagit](https://github.com/nobitagit))
267 |
268 | ## [v0.9.1](https://github.com/richrace/highlight-selected/tree/v0.9.1) (2015-03-01)
269 |
270 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.9.0...v0.9.1)
271 |
272 | **Implemented enhancements:**
273 |
274 | - Minimum length [\#36](https://github.com/richrace/highlight-selected/issues/36)
275 |
276 | **Closed issues:**
277 |
278 | - hide panel on startup [\#54](https://github.com/richrace/highlight-selected/issues/54)
279 | - Atom.Object.defineProperty.get is deprecated. [\#50](https://github.com/richrace/highlight-selected/issues/50)
280 | - Styling has no effect on highlighting [\#41](https://github.com/richrace/highlight-selected/issues/41)
281 |
282 | **Merged pull requests:**
283 |
284 | - Update README example [\#51](https://github.com/richrace/highlight-selected/pull/51) ([tylerdiaz](https://github.com/tylerdiaz))
285 |
286 | ## [v0.9.0](https://github.com/richrace/highlight-selected/tree/v0.9.0) (2015-02-13)
287 |
288 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.8.0...v0.9.0)
289 |
290 | **Closed issues:**
291 |
292 | - Atom.Object.defineProperty.get is deprecated. [\#47](https://github.com/richrace/highlight-selected/issues/47)
293 | - Atom.Object.defineProperty.get is deprecated. [\#45](https://github.com/richrace/highlight-selected/issues/45)
294 | - Atom.Object.defineProperty.get is deprecated. [\#44](https://github.com/richrace/highlight-selected/issues/44)
295 | - Deprecated Selectors [\#42](https://github.com/richrace/highlight-selected/issues/42)
296 | - Atom.Object.defineProperty.get is deprecated. [\#40](https://github.com/richrace/highlight-selected/issues/40)
297 | - Atom.Object.defineProperty.get is deprecated. [\#39](https://github.com/richrace/highlight-selected/issues/39)
298 | - Atom.Object.defineProperty.get is deprecated. [\#38](https://github.com/richrace/highlight-selected/issues/38)
299 | - Atom.Object.defineProperty.get is deprecated. [\#37](https://github.com/richrace/highlight-selected/issues/37)
300 | - Atom.Object.defineProperty.get is deprecated. [\#34](https://github.com/richrace/highlight-selected/issues/34)
301 | - Use new Events API [\#29](https://github.com/richrace/highlight-selected/issues/29)
302 |
303 | **Merged pull requests:**
304 |
305 | - Add minimum length option [\#49](https://github.com/richrace/highlight-selected/pull/49) ([hmatsuda](https://github.com/hmatsuda))
306 | - Fix atom engine semver [\#48](https://github.com/richrace/highlight-selected/pull/48) ([izuzak](https://github.com/izuzak))
307 |
308 | ## [v0.8.0](https://github.com/richrace/highlight-selected/tree/v0.8.0) (2015-02-02)
309 |
310 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.7.0...v0.8.0)
311 |
312 | **Closed issues:**
313 |
314 | - Atom.Object.defineProperty.get is deprecated. [\#35](https://github.com/richrace/highlight-selected/issues/35)
315 |
316 | **Merged pull requests:**
317 |
318 | - Upgrade this package to 1.0 APIs [\#46](https://github.com/richrace/highlight-selected/pull/46) ([hmatsuda](https://github.com/hmatsuda))
319 |
320 | ## [v0.7.0](https://github.com/richrace/highlight-selected/tree/v0.7.0) (2014-12-17)
321 |
322 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.6.3...v0.7.0)
323 |
324 | **Closed issues:**
325 |
326 | - Styles needs an update to support new shadow DOM setting [\#30](https://github.com/richrace/highlight-selected/issues/30)
327 | - Better colors for light theme [\#26](https://github.com/richrace/highlight-selected/issues/26)
328 |
329 | **Merged pull requests:**
330 |
331 | - Fix \#30 [\#33](https://github.com/richrace/highlight-selected/pull/33) ([yongkangchen](https://github.com/yongkangchen))
332 |
333 | ## [v0.6.3](https://github.com/richrace/highlight-selected/tree/v0.6.3) (2014-11-20)
334 |
335 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.6.2...v0.6.3)
336 |
337 | **Closed issues:**
338 |
339 | - option of hideHighlightOnSelectedWord sometimes not work [\#31](https://github.com/richrace/highlight-selected/issues/31)
340 | - Highlights incorrectly positioned [\#28](https://github.com/richrace/highlight-selected/issues/28)
341 |
342 | **Merged pull requests:**
343 |
344 | - fix hideHighlightOnSelectedWord sometimes not work [\#32](https://github.com/richrace/highlight-selected/pull/32) ([yongkangchen](https://github.com/yongkangchen))
345 |
346 | ## [v0.6.2](https://github.com/richrace/highlight-selected/tree/v0.6.2) (2014-09-20)
347 |
348 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.6.1...v0.6.2)
349 |
350 | **Merged pull requests:**
351 |
352 | - implement better colors for light theme [\#27](https://github.com/richrace/highlight-selected/pull/27) ([Bengt](https://github.com/Bengt))
353 |
354 | ## [v0.6.1](https://github.com/richrace/highlight-selected/tree/v0.6.1) (2014-09-15)
355 |
356 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.6.0...v0.6.1)
357 |
358 | **Closed issues:**
359 |
360 | - Editor.getSelection is deprecated. [\#25](https://github.com/richrace/highlight-selected/issues/25)
361 | - Package broken on commit be1d4ee5dc7c125bcd7ffb0f97af6414bcba6e7d of atom [\#23](https://github.com/richrace/highlight-selected/issues/23)
362 | - Ignore 1-char selections [\#22](https://github.com/richrace/highlight-selected/issues/22)
363 |
364 | ## [v0.6.0](https://github.com/richrace/highlight-selected/tree/v0.6.0) (2014-08-23)
365 |
366 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.5...v0.6.0)
367 |
368 | ## [v0.5.5](https://github.com/richrace/highlight-selected/tree/v0.5.5) (2014-08-22)
369 |
370 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.4...v0.5.5)
371 |
372 | **Closed issues:**
373 |
374 | - Leading whitespace [\#21](https://github.com/richrace/highlight-selected/issues/21)
375 | - Highlight Background appears twice in settings [\#20](https://github.com/richrace/highlight-selected/issues/20)
376 |
377 | ## [v0.5.4](https://github.com/richrace/highlight-selected/tree/v0.5.4) (2014-08-19)
378 |
379 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.3...v0.5.4)
380 |
381 | ## [v0.5.3](https://github.com/richrace/highlight-selected/tree/v0.5.3) (2014-08-18)
382 |
383 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.2...v0.5.3)
384 |
385 | ## [v0.5.2](https://github.com/richrace/highlight-selected/tree/v0.5.2) (2014-08-18)
386 |
387 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.1...v0.5.2)
388 |
389 | **Closed issues:**
390 |
391 | - Feature request: highlight words in full color, not only with canvas. [\#15](https://github.com/richrace/highlight-selected/issues/15)
392 | - The highlighted words are almost invisible in light theme [\#14](https://github.com/richrace/highlight-selected/issues/14)
393 |
394 | ## [v0.5.1](https://github.com/richrace/highlight-selected/tree/v0.5.1) (2014-08-18)
395 |
396 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.5.0...v0.5.1)
397 |
398 | ## [v0.5.0](https://github.com/richrace/highlight-selected/tree/v0.5.0) (2014-08-17)
399 |
400 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.4.1...v0.5.0)
401 |
402 | **Closed issues:**
403 |
404 | - Use decorations [\#17](https://github.com/richrace/highlight-selected/issues/17)
405 | - Having highlight-selected installed breaks Atom specs [\#16](https://github.com/richrace/highlight-selected/issues/16)
406 | - If I edit one occurence of the highlighted word it should edit the others too [\#13](https://github.com/richrace/highlight-selected/issues/13)
407 | - Poor performance with large files [\#3](https://github.com/richrace/highlight-selected/issues/3)
408 |
409 | **Merged pull requests:**
410 |
411 | - Decorations [\#19](https://github.com/richrace/highlight-selected/pull/19) ([richrace](https://github.com/richrace))
412 | - Add Ignore Case Option [\#18](https://github.com/richrace/highlight-selected/pull/18) ([andreldm](https://github.com/andreldm))
413 |
414 | ## [v0.4.1](https://github.com/richrace/highlight-selected/tree/v0.4.1) (2014-07-19)
415 |
416 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.4.0...v0.4.1)
417 |
418 | **Implemented enhancements:**
419 |
420 | - Consider current selected don't have border [\#11](https://github.com/richrace/highlight-selected/issues/11)
421 |
422 | **Closed issues:**
423 |
424 | - Uncaught TypeError: Cannot call method 'pixelPositionForScreenPosition' of null -React- [\#10](https://github.com/richrace/highlight-selected/issues/10)
425 |
426 | ## [v0.4.0](https://github.com/richrace/highlight-selected/tree/v0.4.0) (2014-07-03)
427 |
428 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.3.0...v0.4.0)
429 |
430 | **Closed issues:**
431 |
432 | - Cannot call method 'pixelPositionForScreenPosition' of null when using React editor [\#8](https://github.com/richrace/highlight-selected/issues/8)
433 |
434 | **Merged pull requests:**
435 |
436 | - React Editor pixelPositionForScreenPosition fix [\#9](https://github.com/richrace/highlight-selected/pull/9) ([taylorludwig](https://github.com/taylorludwig))
437 |
438 | ## [v0.3.0](https://github.com/richrace/highlight-selected/tree/v0.3.0) (2014-06-29)
439 |
440 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.11...v0.3.0)
441 |
442 | **Merged pull requests:**
443 |
444 | - fix\(marker-view.coffee\): on Windows, lineHeight undefined. [\#6](https://github.com/richrace/highlight-selected/pull/6) ([nickeddy](https://github.com/nickeddy))
445 |
446 | ## [v0.2.11](https://github.com/richrace/highlight-selected/tree/v0.2.11) (2014-04-06)
447 |
448 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.10...v0.2.11)
449 |
450 | ## [v0.2.10](https://github.com/richrace/highlight-selected/tree/v0.2.10) (2014-04-06)
451 |
452 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.9...v0.2.10)
453 |
454 | **Closed issues:**
455 |
456 | - Only highlight whole words [\#5](https://github.com/richrace/highlight-selected/issues/5)
457 |
458 | ## [v0.2.9](https://github.com/richrace/highlight-selected/tree/v0.2.9) (2014-03-22)
459 |
460 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.8...v0.2.9)
461 |
462 | **Closed issues:**
463 |
464 | - Match "$" and "@" [\#4](https://github.com/richrace/highlight-selected/issues/4)
465 |
466 | ## [v0.2.8](https://github.com/richrace/highlight-selected/tree/v0.2.8) (2014-03-15)
467 |
468 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.7...v0.2.8)
469 |
470 | ## [v0.2.7](https://github.com/richrace/highlight-selected/tree/v0.2.7) (2014-03-15)
471 |
472 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.6...v0.2.7)
473 |
474 | ## [v0.2.6](https://github.com/richrace/highlight-selected/tree/v0.2.6) (2014-03-13)
475 |
476 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.5...v0.2.6)
477 |
478 | ## [v0.2.5](https://github.com/richrace/highlight-selected/tree/v0.2.5) (2014-03-05)
479 |
480 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.4...v0.2.5)
481 |
482 | ## [v0.2.4](https://github.com/richrace/highlight-selected/tree/v0.2.4) (2014-03-05)
483 |
484 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.3...v0.2.4)
485 |
486 | **Fixed bugs:**
487 |
488 | - Problem with multiple panes open [\#2](https://github.com/richrace/highlight-selected/issues/2)
489 | - Strange offset with highlight [\#1](https://github.com/richrace/highlight-selected/issues/1)
490 |
491 | ## [v0.2.3](https://github.com/richrace/highlight-selected/tree/v0.2.3) (2014-03-05)
492 |
493 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.2...v0.2.3)
494 |
495 | ## [v0.2.2](https://github.com/richrace/highlight-selected/tree/v0.2.2) (2014-03-04)
496 |
497 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.1...v0.2.2)
498 |
499 | ## [v0.2.1](https://github.com/richrace/highlight-selected/tree/v0.2.1) (2014-03-04)
500 |
501 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.2.0...v0.2.1)
502 |
503 | ## [v0.2.0](https://github.com/richrace/highlight-selected/tree/v0.2.0) (2014-03-04)
504 |
505 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.1.3...v0.2.0)
506 |
507 | ## [v0.1.3](https://github.com/richrace/highlight-selected/tree/v0.1.3) (2014-03-03)
508 |
509 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.1.2...v0.1.3)
510 |
511 | ## [v0.1.2](https://github.com/richrace/highlight-selected/tree/v0.1.2) (2014-03-02)
512 |
513 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.1.1...v0.1.2)
514 |
515 | ## [v0.1.1](https://github.com/richrace/highlight-selected/tree/v0.1.1) (2014-03-02)
516 |
517 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/v0.1.0...v0.1.1)
518 |
519 | ## [v0.1.0](https://github.com/richrace/highlight-selected/tree/v0.1.0) (2014-03-02)
520 |
521 | [Full Changelog](https://github.com/richrace/highlight-selected/compare/6a35111b27d087957b6ec9d0fa56c6b095c11fb2...v0.1.0)
522 |
523 |
524 |
525 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
526 |
--------------------------------------------------------------------------------
/Documentation/Contribute.md:
--------------------------------------------------------------------------------
1 |
2 | # Contributing
3 |
4 | Before you open a pull request, make sure to have all tests pass.
5 |
6 |
7 |
8 | ## Running Tests
9 |
10 | Tests can be run with:
11 |
12 | ```sh
13 | npm run test
14 | ```
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Documentation/Customize.md:
--------------------------------------------------------------------------------
1 |
2 | ## Styling
3 |
4 | If you want to change any of the styling of the region use the following as a guide:
5 |
6 | ```scss
7 | atom-text-editor .highlights {
8 | // Box
9 | .highlight-selected .region {
10 | border-color: #ddd;
11 | border-radius: 3px;
12 | border-width: 1px;
13 | border-style: solid;
14 | }
15 | // Background (set in settings)
16 | .highlight-selected.background .region {
17 | background-color: rgba(155, 149, 0, 0.6);
18 | }
19 | // Light theme box (set in settings)
20 | .highlight-selected.light-theme .region {
21 | border-color: rgba(255, 128, 64, 0.4);
22 | }
23 | // Light theme background (set in settings)
24 | .highlight-selected.light-theme.background .region {
25 | background-color: rgba(255, 128, 64, 0.2);
26 | }
27 | }
28 |
29 | // If you have the Scroll Marker package installed https://atom.io/packages/scroll-marker
30 | // These are the colours that will be shown in the scroller
31 | .highlight-selected-marker-layer.scroll-marker-layer {
32 | .scroll-marker {
33 | background-color: #ffff00;
34 | }
35 | }
36 |
37 | .highlight-selected-selected-marker-layer.scroll-marker-layer {
38 | .scroll-marker {
39 | background-color: #f71010;
40 | }
41 | }
42 | ```
43 |
--------------------------------------------------------------------------------
/Documentation/Keybindings.md:
--------------------------------------------------------------------------------
1 |
2 | ## Commands
3 |
4 | | Command Name | Command Code | Keymap | Description |
5 | | ------------------ | ------------------------------- | ------------------------------------------- | ----------------------------- |
6 | | Toggle | `highlight-selected:toggle` | ctrl+cmd+h | Enables/Disabled this package |
7 | | Select all markers | `highlight-selected:select-all` | | Select all markers |
8 |
9 | To set a Keymap for select all open your `Keymap` file and add:
10 |
11 | ```coffeescript
12 | 'atom-text-editor:not([mini])':
13 | 'cmd-*': 'highlight-selected:select-all'
14 | ```
15 |
--------------------------------------------------------------------------------
/Documentation/Settings.md:
--------------------------------------------------------------------------------
1 |
2 | # Settings
3 |
4 |
5 |
6 | ### Only Highlight Whole Words
7 |
8 | Default : `true`
9 |
10 |
11 |
12 | This uses the `Allowed Characters To Select` option
13 | with Pulsar's `Non-word Characters` to find words.
14 |
15 |
16 |
17 |
18 | ### Hide Highlight On Selected Word
19 |
20 | Default : `false`
21 |
22 |
23 |
24 | Only highlights occurrences, not the selected word.
25 |
26 |
27 |
28 |
29 | ### Ignore Case
30 |
31 | Default : `false`
32 |
33 |
34 |
35 | Matches words even if the case isn't the same.
36 |
37 |
38 |
39 |
40 | ### Light Theme
41 |
42 | Default : `false`
43 |
44 |
45 |
46 | Uses the light theme styling described in [`Customize.md`].
47 |
48 |
49 |
50 |
51 | ### Highlight Background
52 |
53 | Default : `false`
54 |
55 |
56 |
57 | Highlights the background of the matched occurrences.
58 |
59 |
60 |
61 |
62 | ### Minimum Length
63 |
64 | Default : `2`
65 |
66 |
67 |
68 | Minimum length of chars you need to select
69 | before other occurrences are highlighted.
70 |
71 |
72 |
73 |
74 | ### Timeout
75 |
76 | Default : `20`
77 |
78 |
79 |
80 | Stop searching after the given amount of milliseconds.
81 |
82 |
83 |
84 |
85 | ### Highlight In Panes
86 |
87 | Default : `true`
88 |
89 |
90 |
91 | Also highlight in other editor panes.
92 |
93 |
94 |
95 |
96 | ### Show In Status Bar
97 |
98 | Default : `true`
99 |
100 |
101 |
102 | Display the amount of matched
103 | occurrences in the status bar.
104 |
105 |
106 |
107 |
108 | ### Status Bar String
109 |
110 | Default : `Highlighted: %c`
111 |
112 |
113 |
114 | The template for the text shown in the status bar,
115 | at `%c` the number of occurrences is inserted.
116 |
117 |
118 |
119 |
120 | ### Allowed Characters To Select
121 |
122 | Default : `\$@%-`
123 |
124 |
125 |
126 | Non word characters that will be matched in your selection.
127 |
128 | This can be useful in languages like PHP
129 | where variables names start with `$`.
130 |
131 |
132 |
133 |
134 | ### Show Results On Scroll Bar
135 |
136 | Default : `false`
137 |
138 |
139 |
140 | Displays highlighted sections on the scroll bar.
141 |
142 | This requires the **[Scroll Marker]** package.
143 |
144 |
145 |
146 |
147 |
148 |
149 | [`Customize.md`]: Customize.md
150 |
151 | [Scroll Marker]: https://web.pulsar-edit.dev/packages/scroll-marker
152 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2014 Richard Race
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [![Badge Version]][Releases]
7 | [![Badge License]][License]
8 |
9 |
10 |
11 |
12 |
13 |
14 | # Highlight Selected
15 |
16 | *Pulsar package that highlights other*
17 | *occurrences of your current selection.*
18 |
19 |
20 |
21 |
22 | [![Button Customize]][Customize]
23 | [![Button KeyBindings]][KeyBindings]
24 | [![Button Settings]][Settings]
25 |
26 | [![Button Contribute]][Contribute]
27 | [![Button Changelog]][Changelog]
28 |
29 |
30 |
31 |
32 |
33 |
34 | [![Preview]][#]
35 |
36 |
37 |
38 |
39 |
40 | [Releases]: https://github.com/Pulsar-Edit-Highlights/selected/releases
41 | [Package]: https://web.pulsar-edit.dev/packages/highlight-selected
42 | [Actions]: https://github.com/Pulsar-Edit-Highlights/selected/actions
43 |
44 | [Preview]: Resources/Screenshots/Preview.gif
45 | [KeyBindings]: Documentation/KeyBindings.md
46 | [Contribute]: Documentation/Contribute.md
47 | [Changelog]: Documentation/Changelog.md
48 | [Customize]: Documentation/Customize.md
49 | [Settings]: Documentation/Settings.md
50 | [License]: LICENSE
51 |
52 | [#]: #
53 |
54 |
55 |
56 |
57 | [Badge License]: https://img.shields.io/badge/License-MIT-ac8b11.svg?style=for-the-badge&labelColor=yellow&logo=GitBook&logoColor=white
58 | [Badge Version]: https://img.shields.io/github/package-json/v/Pulsar-Edit-Highlights/selected?style=for-the-badge&logo=BookStack&logoColor=white&labelColor=609926&color=4e7a1e
59 | [Badge CI]: https://img.shields.io/github/actions/workflow/status/Pulsar-Edit-Highlights/selected/ci.yml?style=for-the-badge&logo=GitHubActions&logoColor=white&color=582c6d&labelColor=73398D
60 |
61 |
62 |
63 |
64 | [Button KeyBindings]: https://img.shields.io/badge/KeyBindings-3499CD?style=for-the-badge&logoColor=white&logo=AppleArcade
65 | [Button Contribute]: https://img.shields.io/badge/Contribute-7952B3?style=for-the-badge&logoColor=white&logo=GitHub
66 | [Button Changelog]: https://img.shields.io/badge/Changelog-37814A?style=for-the-badge&logoColor=white&logo=GitLFS
67 | [Button Customize]: https://img.shields.io/badge/Customize-00979D?style=for-the-badge&logoColor=white&logo=Rainmeter
68 | [Button Settings]: https://img.shields.io/badge/Settings-yellow?style=for-the-badge&logoColor=white&logo=AzureArtifacts
69 |
--------------------------------------------------------------------------------
/Resources/Keymap.json:
--------------------------------------------------------------------------------
1 | {
2 | "atom-text-editor" : {
3 | "ctrl-cmd-h" : "highlight-selected:toggle"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Resources/Menus.json:
--------------------------------------------------------------------------------
1 | {
2 | "menu" : [{
3 |
4 | "label" : "Packages" ,
5 |
6 | "submenu" : [{
7 |
8 | "label" : "Highlight Selected" ,
9 |
10 | "submenu" : [{
11 | "command" : "highlight-selected:toggle" ,
12 | "label" : "Toggle"
13 | }]
14 | }]
15 | }]
16 | }
17 |
--------------------------------------------------------------------------------
/Resources/Screenshots/Preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pulsar-Edit-Highlights/selected/1f940a0588cdd84aaee576d864516f264183fec5/Resources/Screenshots/Preview.gif
--------------------------------------------------------------------------------
/Resources/Stylesheet.less:
--------------------------------------------------------------------------------
1 |
2 | @import 'ui-variables';
3 |
4 |
5 | atom-text-editor .highlights {
6 |
7 | .highlight.highlight-selected .region {
8 |
9 | background-color : transparent ;
10 | pointer-events : none ;
11 | box-sizing : border-box ;
12 | position : absolute ;
13 | z-index : -1 ;
14 | }
15 |
16 |
17 | // Box
18 |
19 | .highlight-selected .region {
20 |
21 | border-radius : 3px ;
22 | border-color : #ddd ;
23 | border-style : solid ;
24 | border-width : 1px ;
25 | }
26 |
27 |
28 | /*
29 | * Background
30 | * ( Set in settings )
31 | */
32 |
33 | .highlight-selected.background .region {
34 | background-color : rgba( 155 , 149 , 0 , 0.6 ) ;
35 | }
36 |
37 |
38 | /*
39 | * Light Theme Box
40 | * ( Set in settings )
41 | */
42 |
43 | .highlight-selected.light-theme .region {
44 | border-color : rgba( 255 , 128 , 64 , 0.4 ) ;
45 | }
46 |
47 |
48 | /*
49 | * Light Theme Background
50 | * ( Set in settings )
51 | */
52 |
53 | .highlight-selected.light-theme.background .region {
54 | background-color : rgba( 255 , 128 , 64 , 0.2 ) ;
55 | }
56 | }
57 |
58 |
59 | status-bar {
60 |
61 | .highlight-selected-status {
62 | display : inline-block ;
63 | }
64 |
65 | .highlight-selected-hidden {
66 | display : none ;
67 | }
68 | }
69 |
70 |
71 | .highlight-selected-marker-layer.scroll-marker-layer {
72 |
73 | .scroll-marker {
74 | background-color : #ffff00 ;
75 | }
76 | }
77 |
78 |
79 | .highlight-selected-selected-marker-layer.scroll-marker-layer {
80 |
81 | .scroll-marker {
82 | background-color : #f71010 ;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Source/App.js:
--------------------------------------------------------------------------------
1 | const { CompositeDisposable } = require('atom');
2 | const ScrollMarkersService = require('./scroll-markers/scroll-markers-service');
3 | const StatusBarService = require('./status-bar/status-bar-service');
4 | const SelectionManager = require('./selection-manager');
5 |
6 |
7 | const { commands } = atom;
8 |
9 |
10 | module.exports = {
11 |
12 | selectionManager: null,
13 |
14 | activate (){
15 |
16 | this.selectionManager = new SelectionManager;
17 | this.subscriptions = new CompositeDisposable;
18 |
19 | this.subscriptions.add(this.listenForCommands());
20 |
21 | this.scrollMarkersService = new ScrollMarkersService(this.selectionManager);
22 | },
23 |
24 | deactivate (){
25 |
26 | this.scrollMarkersService?.destroy();
27 | this.selectionManager?.destroy();
28 | this.statusBarService?.destroy();
29 | this.subscriptions?.dispose();
30 |
31 | this.scrollMarkersService = null;
32 | this.selectionManager = null;
33 | this.statusBarService = null;
34 | this.subscriptions = null;
35 | },
36 |
37 | provideHighlightSelectedV1Deprecated (){
38 | return this.selectionManager
39 | },
40 |
41 | provideHighlightSelectedV2 (){
42 | return this.selectionManager
43 | },
44 |
45 | consumeStatusBar(statusBar){
46 | this.statusBarService =
47 | new StatusBarService(statusBar,this.selectionManager);
48 | },
49 |
50 | toggle (){
51 | return (this.selectionManager.disabled)
52 | ? this.selectionManager.enable()
53 | : this.selectionManager.disable()
54 | },
55 |
56 | selectAll (){
57 | return this.selectionManager.selectAll()
58 | },
59 |
60 | consumeScrollMarker ( scrollMarkerAPI ){
61 | this.scrollMarkersService
62 | .setScrollMarkerAPI(scrollMarkerAPI);
63 | },
64 |
65 | listenForCommands (){
66 | return commands.add('atom-workspace',{
67 | 'highlight-selected:select-all': () => this.selectAll() ,
68 | 'highlight-selected:toggle': () => this.toggle()
69 | })
70 | }
71 | };
72 |
--------------------------------------------------------------------------------
/Source/errors/early-termination-signal.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | class EarlyTerminationSignal extends Error {}
4 |
5 |
6 | module.exports = EarlyTerminationSignal;
7 |
--------------------------------------------------------------------------------
/Source/scroll-markers/scroll-markers-service.js:
--------------------------------------------------------------------------------
1 |
2 | const { CompositeDisposable } = require('atom');
3 |
4 |
5 | const { workspace , config } = atom;
6 |
7 |
8 |
9 | const showResultsOnScrollbar = () =>
10 | config.get('highlight-selected.showResultsOnScrollBar');
11 |
12 |
13 |
14 | module.exports = class ScrollMarkersService {
15 |
16 | static ensureScrollViewInstalled (){
17 |
18 | if( atom.inSpecMode() )
19 | return
20 |
21 | require('atom-package-deps')
22 | .install('highlight-selected',true);
23 | }
24 |
25 |
26 | editorSubscriptions = new CompositeDisposable;
27 | selectionManager;
28 | configObserver;
29 | api;
30 |
31 |
32 | constructor ( selectionManager ){
33 |
34 | this.selectionManager = selectionManager;
35 |
36 | if( showResultsOnScrollbar() ){
37 |
38 | ScrollMarkersService.ensureScrollViewInstalled();
39 |
40 | workspace
41 | .getTextEditors()
42 | .forEach((editor) => this.setScrollMarkerView(editor));
43 | }
44 |
45 | this.editorSubscriptions
46 | .add( ... this.setupEditorSubscriptions() );
47 |
48 | this.setupConfigObserver();
49 | }
50 |
51 |
52 | destroy (){
53 | this.configObserver.dispose();
54 | this.editorSubscriptions.dispose();
55 | }
56 |
57 |
58 | setScrollMarkerAPI ( api ){
59 | this.api = api;
60 | }
61 |
62 |
63 | * setupEditorSubscriptions (){
64 |
65 | yield workspace
66 | .observeTextEditors((editor) =>
67 | this.setScrollMarkerView(editor));
68 |
69 | yield workspace
70 | .onWillDestroyPaneItem(({ item }) => {
71 |
72 | if( item.constructor.name !== 'TextEditor' )
73 | return
74 |
75 | this.destroyScrollMarkers(item);
76 | });
77 | }
78 |
79 |
80 | setupConfigObserver (){
81 |
82 | const onChange = ( enabled ) => {
83 |
84 | if( enabled )
85 | ScrollMarkersService.ensureScrollViewInstalled();
86 |
87 | const processMarkers = ( enabled )
88 | ? ( editor ) => this.setScrollMarkerView(editor)
89 | : ( editor ) => this.destroyScrollMarkers(editor) ;
90 |
91 | workspace
92 | .getTextEditors()
93 | .forEach(processMarkers);
94 | }
95 |
96 | this.configObserver = config
97 | .observe('highlight-selected.showResultsOnScrollBar',onChange);
98 | }
99 |
100 |
101 | setScrollMarkerView ( editor ){
102 |
103 | if( ! showResultsOnScrollbar() )
104 | return
105 |
106 |
107 | const { selectionManager , api } = this;
108 |
109 | if( ! api )
110 | return
111 |
112 |
113 | const view = api
114 | .scrollMarkerViewForEditor(editor);
115 |
116 | const { selectedMarkerLayer , visibleMarkerLayer } =
117 | selectionManager.editorToMarkerLayerMap[editor.id];
118 |
119 | view
120 | .getLayer('highlight-selected-marker-layer')
121 | .syncToMarkerLayer(visibleMarkerLayer);
122 |
123 | view
124 | .getLayer('highlight-selected-selected-marker-layer')
125 | .syncToMarkerLayer(selectedMarkerLayer);
126 | }
127 |
128 |
129 | destroyScrollMarkers ( editor ){
130 |
131 | const { api } = this;
132 |
133 | if( ! api )
134 | return
135 |
136 | api
137 | .scrollMarkerViewForEditor(editor)
138 | .destroy();
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/Source/search-model.js:
--------------------------------------------------------------------------------
1 |
2 | const { getActiveEditor, getActiveEditors } = require('./utils/editor-finders');
3 | const EarlyTerminationSignal = require('./errors/early-termination-signal');
4 | const getNonWordCharacters = require('./utils/non-word-characters');
5 | const isWordSelected = require('./utils/is-word-selected');
6 | const escapeRegExp = require('./utils/escape-reg-exp');
7 |
8 |
9 | const { config } = atom;
10 |
11 |
12 | module.exports = class SearchModel {
13 |
14 | static hideHighlightOnSelectedWord ( range , selections ){
15 |
16 | if( ! config.get('highlight-selected.hideHighlightOnSelectedWord') )
17 | return false;
18 |
19 | let outcome = false;
20 |
21 | for( let i = 0 ; i < selections.length ; i += 1 ){
22 |
23 | const selection = selections[i];
24 | const selectionRange = selection.getBufferRange();
25 |
26 | outcome =
27 | range.start.column === selectionRange.start.column &&
28 | range.start.row === selectionRange.start.row &&
29 | range.end.column === selectionRange.end.column &&
30 | range.end.row === selectionRange.end.row;
31 |
32 | if( outcome )
33 | break;
34 | }
35 |
36 | return outcome
37 | }
38 |
39 |
40 | static makeClasses (){
41 |
42 | let className = 'highlight-selected';
43 |
44 | if( config.get('highlight-selected.lightTheme') )
45 | className += ' light-theme';
46 |
47 | if( config.get('highlight-selected.highlightBackground') )
48 | className += ' background';
49 |
50 | return className
51 | }
52 |
53 |
54 | // This functions replicates `\bTEXT\b` regex with allowed non-word characters to be something
55 | // like: `(^|[ @$#\.])TEXT([ @$#\.]|$)`. This allows unicode characters to be highlighted. Also,
56 | // it allows characters such as `@` in Ruby to selected and highlighted.
57 | // This is the first part of highlighting the whole words. We need to run another regex later to
58 | // ensure we only highlight the selection from the Atom Editor.
59 |
60 | static updateRegexSearchForWholeWords (
61 | regexSearch , editor , lastSelection ,
62 | regexFlags , text ){
63 |
64 | if( ! config.get('highlight-selected.onlyHighlightWholeWords') )
65 | return regexSearch
66 |
67 | if( ! isWordSelected(editor,lastSelection))
68 | return regexSearch
69 |
70 |
71 | const selectionStart = lastSelection
72 | .getBufferRange().start;
73 |
74 | const nonWordCharacters =
75 | getNonWordCharacters(editor,selectionStart);
76 |
77 | const allowedCharactersToSelect = config
78 | .get('highlight-selected.allowedCharactersToSelect');
79 |
80 | const nonWordCharactersToStrip = nonWordCharacters
81 | .replace(new RegExp(`[${allowedCharactersToSelect}]`,'g'),'');
82 |
83 | const regexForWholeWord =
84 | new RegExp(`[ \\t${escapeRegExp(nonWordCharactersToStrip)}]`,regexFlags);
85 |
86 |
87 | if( regexForWholeWord.test(text) )
88 | return regexSearch
89 |
90 | return `(?:[ \\t${
91 | escapeRegExp(nonWordCharacters)
92 | }]|^)(${
93 | regexSearch
94 | })(?=[ \\t${
95 | escapeRegExp(nonWordCharacters)
96 | }]|$)`;
97 | }
98 |
99 |
100 | constructor ( selectionManager ){
101 | this.selectionManager = selectionManager;
102 | }
103 |
104 |
105 | handleSelection (){
106 |
107 | const editor = getActiveEditor();
108 |
109 | if( ! editor )
110 | return
111 |
112 | this.selectionManager.removeAllMarkers();
113 |
114 | if( this.selectionManager.disabled )
115 | return;
116 |
117 | if( editor.getLastSelection().isEmpty() )
118 | return;
119 |
120 |
121 | this.selections = editor
122 | .getSelections();
123 |
124 | const lastSelection = editor
125 | .getLastSelection();
126 |
127 | const text = lastSelection
128 | .getText();
129 |
130 |
131 | if( text.length < config.get('highlight-selected.minimumLength') )
132 | return
133 |
134 | if( text.includes('\n') )
135 | return
136 |
137 | const regex = new RegExp('^\\s+$');
138 |
139 | if( regex.test(text) )
140 | return
141 |
142 | let regexFlags = 'g';
143 |
144 | if( config.get('highlight-selected.ignoreCase') )
145 | regexFlags += 'i';
146 |
147 | const regexSearch = SearchModel
148 | .updateRegexSearchForWholeWords(
149 | escapeRegExp(text) ,
150 | editor ,
151 | lastSelection ,
152 | regexFlags ,
153 | text
154 | );
155 |
156 | this.selectionManager.resultCount = 0;
157 |
158 | if( config.get('highlight-selected.highlightInPanes') ){
159 |
160 | const originalEditor = editor;
161 |
162 | for ( const editor of getActiveEditors() )
163 | this.highlightSelectionInEditor( editor , regexSearch , regexFlags , originalEditor );
164 |
165 | } else {
166 | this.highlightSelectionInEditor(editor,regexSearch,regexFlags);
167 | }
168 |
169 | this.selectionManager.emitter.emit('did-finish-adding-markers');
170 | }
171 |
172 |
173 | highlightSelectionInEditor ( editor , regexSearch , regexFlags , originalEditor ){
174 |
175 | const maximumHighlights = atom.config
176 | .get('highlight-selected.maximumHighlights');
177 |
178 | if( this.selectionManager.resultCount > maximumHighlights )
179 | return
180 |
181 | const markerLayers = this.selectionManager
182 | .editorToMarkerLayerMap[editor.id];
183 |
184 | if( ! markerLayers )
185 | return
186 |
187 | const markerLayer = markerLayers.visibleMarkerLayer;
188 | const markerLayerForHiddenMarkers = markerLayers.selectedMarkerLayer;
189 |
190 | // We should have a marker layers. If not run away.
191 |
192 | if( ! markerLayer )
193 | return
194 |
195 | if( ! markerLayerForHiddenMarkers )
196 | return
197 |
198 | // HACK: `editor.scan` is a synchronous process which iterates the entire buffer,
199 | // executing a regex against every line and yielding each match. This can be
200 | // costly for very large files with many matches.
201 | //
202 | // While we can and do limit the maximum number of highlight markers,
203 | // `editor.scan` cannot be terminated early, meaning that we are forced to
204 | // pay the cost of iterating every line in the file, running the regex, and
205 | // returning matches, even if we shouldn't be creating any more markers.
206 | //
207 | // Instead, throw an exception. This isn't pretty, but it prevents the
208 | // scan from running to completion unnecessarily.
209 |
210 | try {
211 |
212 | editor.scan(new RegExp(regexSearch,regexFlags),(result) => {
213 |
214 | if( this.selectionManager.resultCount >= maximumHighlights )
215 | throw new EarlyTerminationSignal
216 |
217 | let newResult = result;
218 |
219 | // The the following check allows the selection from the Atom Editor to have the marker on
220 | // it. If we do not redo the regex and update the found match, we will add a marker around
221 | // all non-word characters, rather than the allowed non-word characters.
222 |
223 | if( config.get('highlight-selected.onlyHighlightWholeWords') )
224 | editor.scanInBufferRange(new RegExp(escapeRegExp(result.match[1])), result.range, (e) => newResult = e);
225 |
226 | if( ! newResult )
227 | return
228 |
229 | this.selectionManager.resultCount += 1;
230 |
231 | const hideHighlight = SearchModel
232 | .hideHighlightOnSelectedWord( newResult.range , this.selections );
233 |
234 | // If we want to hide the highlight on the selected word, we will add it to a different
235 | // marker layer. The hidden marker layer is used for by the `scroll-marker` API to show
236 | // matches. We do not tell the editor to decorate this marker layer. We also use fire
237 | // different events. This is so other packages and render them differently if they want.
238 |
239 | if( hideHighlight && originalEditor?.id === editor.id ){
240 |
241 | const marker = markerLayerForHiddenMarkers.markBufferRange(newResult.range);
242 |
243 | this.selectionManager.emitter.emit('did-add-selected-marker', marker);
244 | this.selectionManager.emitter.emit('did-add-selected-marker-for-editor',{ marker , editor });
245 |
246 | } else {
247 |
248 | const marker = markerLayer.markBufferRange(newResult.range);
249 |
250 | this.selectionManager.emitter.emit('did-add-marker', marker);
251 | this.selectionManager.emitter.emit('did-add-marker-for-editor',{ marker , editor });
252 | }
253 | });
254 |
255 | } catch ( error ){
256 |
257 | if( error instanceof EarlyTerminationSignal ){
258 |
259 | // If this is an early termination, just continue on.
260 |
261 | } else
262 | if( error.message === 'regular expression is too large' ){
263 |
264 | // User has done a huge selection which exceed regex limit.
265 | // The user is most probably about to take action on the huge selection
266 | // by pressing ctrl-c or backspace … the user currently does not care about highlighting.
267 | // Therefore just continue on.
268 |
269 | } else {
270 | throw error;
271 | }
272 | }
273 |
274 | editor.decorateMarkerLayer(markerLayer,{
275 | class : SearchModel.makeClasses() ,
276 | type : 'highlight'
277 | })
278 | }
279 | };
280 |
--------------------------------------------------------------------------------
/Source/selection-manager.js:
--------------------------------------------------------------------------------
1 |
2 | const { CompositeDisposable, Emitter } = require('atom');
3 | const { getActiveEditor } = require('./utils/editor-finders');
4 | const SearchModel = require('./search-model');
5 | const debounce = require('debounce');
6 |
7 |
8 | const { workspace , config } = atom;
9 |
10 |
11 | module.exports = class SelectionManager {
12 |
13 | editorToMarkerLayerMap = [];
14 | markerLayer = [];
15 | resultCount = 0;
16 | emitter = new Emitter;
17 |
18 |
19 | constructor (){
20 |
21 | this.debouncedHandleSelection = this.debouncedHandleSelection.bind(this);
22 |
23 | this.searchModel = new SearchModel(this);
24 |
25 | this.editorSubscriptions = new CompositeDisposable;
26 | this.editorSubscriptions.add(
27 | workspace.observeTextEditors(
28 | (editor) => this.setupMarkerLayers(editor)));
29 |
30 | this.editorSubscriptions.add(
31 | workspace.onWillDestroyPaneItem((item) => {
32 |
33 | if( item.item.constructor.name !== 'TextEditor' )
34 | return
35 |
36 | const editor = item.item;
37 | this.removeMarkers(editor.id);
38 |
39 | delete this.editorToMarkerLayerMap[editor.id];
40 | })
41 | );
42 |
43 | this.enable();
44 | this.listenForTimeoutChange();
45 |
46 | this.activeItemSubscription = workspace
47 | .onDidChangeActivePaneItem(() => {
48 | this.debouncedHandleSelection();
49 | return this.subscribeToActiveTextEditor();
50 | });
51 |
52 | this.subscribeToActiveTextEditor();
53 | }
54 |
55 |
56 | destroy (){
57 |
58 | this.handleSelectionDebounce.clear();
59 | this.activeItemSubscription.dispose();
60 |
61 | this.selectionSubscription?.dispose();
62 | this.editorSubscriptions?.dispose();
63 | }
64 |
65 | onDidAddMarker ( callback ){
66 | const Grim = require('grim'); // eslint-disable-line global-require
67 | Grim.deprecate('Please do not use. This method will be removed.');
68 | this.emitter.on('did-add-marker',callback);
69 | }
70 |
71 | onDidAddSelectedMarker ( callback ){
72 |
73 | const Grim = require('grim');
74 | Grim.deprecate('Please do not use. This method will be removed.');
75 | this.emitter.on('did-add-selected-marker',callback);
76 | }
77 |
78 | onDidAddMarkerForEditor ( callback ){
79 | this.emitter.on('did-add-marker-for-editor',callback);
80 | }
81 |
82 | onDidAddSelectedMarkerForEditor ( callback ){
83 | this.emitter.on('did-add-selected-marker-for-editor',callback);
84 | }
85 |
86 | onDidFinishAddingMarkers ( callback ){
87 | this.emitter.on('did-finish-adding-markers',callback);
88 | }
89 |
90 | onDidRemoveAllMarkers ( callback ){
91 | this.emitter.on('did-remove-marker-layer',callback);
92 | }
93 |
94 |
95 | disable (){
96 | this.disabled = true;
97 | return this.removeAllMarkers()
98 | }
99 |
100 |
101 | enable (){
102 | this.disabled = false;
103 | return this.debouncedHandleSelection()
104 | }
105 |
106 |
107 | debouncedHandleSelection (){
108 |
109 | if( ! this.handleSelectionDebounce ){
110 |
111 | this.handleSelectionDebounce = debounce(() => {
112 | this.searchModel.handleSelection();
113 | },config.get('highlight-selected.timeout'));
114 | }
115 |
116 | return this.handleSelectionDebounce()
117 | }
118 |
119 |
120 | listenForTimeoutChange (){
121 | return config.onDidChange('highlight-selected.timeout',
122 | () => this.debouncedHandleSelection());
123 | }
124 |
125 |
126 | subscribeToActiveTextEditor (){
127 |
128 | this.selectionSubscription
129 | ?.dispose();
130 |
131 | const editor = getActiveEditor();
132 |
133 | if( ! editor )
134 | return
135 |
136 | this.selectionSubscription =
137 | new CompositeDisposable;
138 |
139 | this.selectionSubscription.add(
140 | editor.onDidAddSelection(
141 | this.debouncedHandleSelection));
142 |
143 | this.selectionSubscription.add(
144 | editor.onDidChangeSelectionRange(
145 | this.debouncedHandleSelection));
146 |
147 | this.searchModel.handleSelection();
148 | }
149 |
150 |
151 | removeAllMarkers (){
152 |
153 | for ( const editorId in this.editorToMarkerLayerMap )
154 | this.removeMarkers(editorId);
155 | }
156 |
157 |
158 | removeMarkers ( editorId ){
159 |
160 | const layerMap = this.editorToMarkerLayerMap[ editorId ];
161 |
162 | if( ! layerMap )
163 | return;
164 |
165 | const { visibleMarkerLayer , selectedMarkerLayer } = layerMap;
166 |
167 | selectedMarkerLayer.clear();
168 | visibleMarkerLayer.clear();
169 |
170 | this.resultCount = 0;
171 | this.emitter.emit('did-remove-marker-layer');
172 | }
173 |
174 |
175 | selectAll (){
176 |
177 | const editor = getActiveEditor();
178 | const markerLayers = this.editorToMarkerLayerMap[editor.id];
179 |
180 | if( ! markerLayers )
181 | return
182 |
183 | const ranges = [ 'visibleMarkerLayer' , 'selectedMarkerLayer' ]
184 | .map(( key ) => this.markerLayer[key])
185 | .map(( layer ) => layer.getMarkers())
186 | .flat()
187 | .map(( marker ) => marker.getBufferRange());
188 |
189 | if( ranges.length > 0 )
190 | editor.setSelectedBufferRanges(ranges,{ flash : true });
191 | }
192 |
193 |
194 | setupMarkerLayers ( editor ){
195 |
196 | const { id } = editor;
197 |
198 | // const layerMap = ( this.editorToMarkerLayerMap[ id ] ??= {} );
199 |
200 | // layerMap.selectedMarkerLayer
201 | // ??= editor.addMarkerLayer();
202 |
203 | // layerMap.visibleMarkerLayer
204 | // ??= editor.addMarkerLayer();
205 |
206 | const layerMap = this.editorToMarkerLayerMap[ id ] ?? {};
207 |
208 | if( ! layerMap.selectedMarkerLayer )
209 | layerMap.selectedMarkerLayer = editor.addMarkerLayer();
210 |
211 | if( ! layerMap.visibleMarkerLayer )
212 | layerMap.visibleMarkerLayer = editor.addMarkerLayer();
213 |
214 | this.editorToMarkerLayerMap[ id ] = layerMap;
215 | }
216 | };
217 |
--------------------------------------------------------------------------------
/Source/status-bar/status-bar-service.js:
--------------------------------------------------------------------------------
1 |
2 | const StatusBarView = require('./status-bar-view');
3 |
4 |
5 | const { config } = atom;
6 |
7 |
8 | class StatusBarService {
9 |
10 | constructor ( statusBar , selectionManager ){
11 |
12 | this.selectionManager = selectionManager;
13 | this.statusBar = statusBar;
14 |
15 | this.updateCount = this.updateCount.bind(this);
16 |
17 | this.listenForStatusBarConfigChange();
18 | this.setupListeners();
19 | this.setupStatusBarView();
20 | }
21 |
22 |
23 | destroy (){
24 |
25 | this.removeStatusBarView();
26 |
27 | this.selectionSubscription?.dispose();
28 | }
29 |
30 |
31 | listenForStatusBarConfigChange (){
32 | return config.onDidChange('highlight-selected.showInStatusBar',( changed ) => {
33 | return ( changed.newValue )
34 | ? this.setupStatusBarView()
35 | : this.removeStatusBarView()
36 | });
37 | }
38 |
39 |
40 | setupListeners (){
41 |
42 | const { selectionManager } = this;
43 |
44 | selectionManager.onDidFinishAddingMarkers(this.updateCount);
45 | selectionManager.onDidRemoveAllMarkers(this.updateCount);
46 | }
47 |
48 |
49 | setupStatusBarView (){
50 |
51 | if( this.statusBarElement )
52 | return
53 |
54 | if( ! config.get('highlight-selected.showInStatusBar') )
55 | return
56 |
57 | this.statusBarElement =
58 | new StatusBarView;
59 |
60 | this.statusBarTile = this.statusBar
61 | .addLeftTile({
62 | priority : 100 ,
63 | item : this.statusBarElement.element
64 | })
65 | }
66 |
67 |
68 | removeStatusBarView (){
69 |
70 | if( ! this.statusBarElement)
71 | return
72 |
73 | this.statusBarElement.removeElement();
74 | this.statusBarTile?.destroy();
75 |
76 | this.statusBarElement = null;
77 | this.statusBarTile = null;
78 | }
79 |
80 |
81 | updateCount (){
82 |
83 | const { statusBarElement , selectionManager } = this;
84 |
85 | statusBarElement?.updateCount(
86 | selectionManager.resultCount);
87 | }
88 | }
89 |
90 |
91 |
92 | module.exports = StatusBarService;
93 |
--------------------------------------------------------------------------------
/Source/status-bar/status-bar-view.js:
--------------------------------------------------------------------------------
1 |
2 | const { config } = atom;
3 |
4 |
5 | module.exports = class StatusBarView {
6 |
7 | constructor (){
8 |
9 | this.removeElement = this.removeElement.bind(this);
10 |
11 | this.element = document.createElement('div');
12 |
13 | this.element.classList
14 | .add('highlight-selected-status','inline-block');
15 | }
16 |
17 | updateCount ( count ){
18 |
19 | const statusBarString = config
20 | .get('highlight-selected.statusBarString');
21 |
22 | this.element.textContent =
23 | statusBarString.replace('%c',count);
24 |
25 | const { classList } = this.element;
26 |
27 | if( count > 0 )
28 | classList.remove('highlight-selected-hidden');
29 | else
30 | classList.add('highlight-selected-hidden');
31 | }
32 |
33 | removeElement (){
34 |
35 | this.element.parentNode
36 | .removeChild(this.element);
37 |
38 | this.element = null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Source/utils/editor-finders.js:
--------------------------------------------------------------------------------
1 |
2 | const { workspace } = atom;
3 |
4 |
5 | function getActiveEditor (){
6 | return workspace.getActiveTextEditor();
7 | }
8 |
9 |
10 | const isTextEditor = ( item ) =>
11 | item?.constructor.name === 'TextEditor';
12 |
13 |
14 | function getActiveEditors (){
15 | return workspace
16 | .getPanes()
17 | .map(({ activeItem }) => activeItem)
18 | .filter(isTextEditor)
19 | }
20 |
21 |
22 |
23 | module.exports = { getActiveEditor , getActiveEditors }
24 |
--------------------------------------------------------------------------------
/Source/utils/escape-reg-exp.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | const unescaped = /[-/\\^$*+?.()|[\]{}]/g;
4 |
5 | const escaped = '\\$&';
6 |
7 |
8 | function escapeRegExp ( string = '' ){
9 | return string
10 | .replace(unescaped,escaped)
11 | }
12 |
13 |
14 | module.exports = escapeRegExp;
15 |
--------------------------------------------------------------------------------
/Source/utils/is-word-selected.js:
--------------------------------------------------------------------------------
1 |
2 | const getNonWordCharacters = require('./non-word-characters');
3 | const escapeRegExp = require('./escape-reg-exp');
4 | const { Range } = require('atom');
5 |
6 |
7 | function isNonWord ( editor , range ){
8 |
9 | const { start } = range;
10 |
11 | const nonWords = escapeRegExp(
12 | getNonWordCharacters(editor,start));
13 |
14 | const pattern =
15 | new RegExp(`[ \t${ nonWords }]`);
16 |
17 | const text = editor
18 | .getTextInBufferRange(range);
19 |
20 | return pattern
21 | .test(text)
22 | }
23 |
24 |
25 | function isNonWordCharacterToTheLeft ( editor , selection ){
26 |
27 | const { start } = selection
28 | .getBufferRange();
29 |
30 | const range = Range
31 | .fromPointWithDelta(start,0,-1);
32 |
33 | return isNonWord(editor,range)
34 | }
35 |
36 |
37 | function isNonWordCharacterToTheRight ( editor , selection ){
38 |
39 | const { end } = selection
40 | .getBufferRange();
41 |
42 | const range = Range
43 | .fromPointWithDelta(end,0,1);
44 |
45 | return isNonWord(editor,range);
46 | }
47 |
48 |
49 | function isWordSelected ( editor , selection ){
50 |
51 | const range = selection
52 | .getBufferRange();
53 |
54 | if( ! range.isSingleLine() )
55 | return false;
56 |
57 |
58 | const { start , end } = range;
59 |
60 | const lineRange = editor
61 | .bufferRangeForBufferRow(start.row);
62 |
63 | const nonWordCharacterToTheLeft =
64 | start.isEqual(lineRange.start) ||
65 | isNonWordCharacterToTheLeft(editor,selection);
66 |
67 | const nonWordCharacterToTheRight =
68 | end.isEqual(lineRange.end) ||
69 | isNonWordCharacterToTheRight(editor,selection);
70 |
71 | return nonWordCharacterToTheRight
72 | && nonWordCharacterToTheLeft
73 | }
74 |
75 |
76 | module.exports = isWordSelected;
77 |
--------------------------------------------------------------------------------
/Source/utils/non-word-characters.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | const { config } = atom;
4 |
5 |
6 | function getNonWordCharacters ( editor , point ){
7 |
8 | const scope = editor
9 | .scopeDescriptorForBufferPosition(point);
10 |
11 | const nonWordCharacters = config
12 | .get('editor.nonWordCharacters',{ scope });
13 |
14 | return nonWordCharacters;
15 | }
16 |
17 |
18 | module.exports = getNonWordCharacters;
19 |
--------------------------------------------------------------------------------
/Tests/fixtures/hex.md:
--------------------------------------------------------------------------------
1 | 00000000 00000000 00000000
2 | 00000000.00000000.00000000
3 | 00000000-00000000-00000000
4 |
5 | 00000000 00000000 00000000
6 | 00000000..00000000..00000000
7 | 00000000--00000000--00000000
8 |
--------------------------------------------------------------------------------
/Tests/fixtures/sample.coffee:
--------------------------------------------------------------------------------
1 | # Sample file for ensuring the regions get added.
2 | # Output Fizz on multiples of 3, Output Buzz on multiples of 5
3 | # Output FizzBuzz on multiples of 3 and 5
4 |
5 | output = ""
6 |
7 | i = 1
8 | while i <= 100
9 | string = "#{i} "
10 | string += 'Fizz' if i % 3 is 0
11 | string += 'Buzz' if i % 5 is 0
12 | output += "#{string}\n"
13 | i++
14 |
--------------------------------------------------------------------------------
/Tests/fixtures/sample.php:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/Tests/highlight-selected-spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const { Range, Point } = require('atom');
3 |
4 | // This spec is more of an end-to-end test.
5 | describe('HighlightSelected', () => {
6 | let [
7 | workspaceElement,
8 | minimap,
9 | editor,
10 | editorElement,
11 | highlightSelected,
12 | minimapHS,
13 | minimapModule,
14 | ] = Array.from([]);
15 |
16 | const hasMinimap =
17 | atom.packages.getAvailablePackageNames().indexOf('minimap') !== -1 &&
18 | atom.packages.getAvailablePackageNames().indexOf('minimap-highlight-selected') !== -1;
19 |
20 | beforeEach(() => {
21 | workspaceElement = atom.views.getView(atom.workspace);
22 | atom.project.setPaths([path.join(__dirname, 'fixtures')]);
23 | });
24 |
25 | afterEach(() => {
26 | highlightSelected.deactivate();
27 | if (minimapHS) {
28 | minimapHS.deactivate();
29 | }
30 | if (minimapModule) {
31 | minimapModule.deactivate();
32 | }
33 | });
34 |
35 | describe('when opening a coffee file', () => {
36 | beforeEach(() => {
37 | waitsForPromise(() =>
38 | atom.packages.activatePackage('status-bar').then(() => {
39 | workspaceElement.querySelector('status-bar');
40 | })
41 | );
42 |
43 | waitsForPromise(() =>
44 | atom.packages.activatePackage('highlight-selected').then(({ mainModule }) => {
45 | highlightSelected = mainModule;
46 | })
47 | );
48 |
49 | if (hasMinimap) {
50 | waitsForPromise(() =>
51 | atom.packages.activatePackage('minimap').then(({ mainModule }) => {
52 | minimapModule = mainModule;
53 | })
54 | );
55 | waitsForPromise(() =>
56 | atom.packages.activatePackage('minimap-highlight-selected').then(({ mainModule }) => {
57 | minimapHS = mainModule;
58 | })
59 | );
60 | }
61 |
62 | waitsForPromise(() =>
63 | atom.workspace.open('sample.coffee').then(
64 | () => null,
65 | (error) => {
66 | throw error.stack;
67 | }
68 | )
69 | );
70 |
71 | runs(() => {
72 | jasmine.attachToDOM(workspaceElement);
73 | editor = atom.workspace.getActiveTextEditor();
74 | editorElement = atom.views.getView(editor);
75 | editorElement.setHeight(250);
76 | editorElement.component.measureDimensions();
77 | });
78 | });
79 |
80 | describe('updates debounce when config is changed', () => {
81 | beforeEach(() => {
82 | spyOn(highlightSelected.selectionManager, 'debouncedHandleSelection');
83 | atom.config.set('highlight-selected.timeout', 20000);
84 | });
85 |
86 | it('calls createDebouce', () => {
87 | expect(highlightSelected.selectionManager.debouncedHandleSelection).toHaveBeenCalled();
88 | });
89 | });
90 |
91 | describe('when a whole word is selected', () => {
92 | beforeEach(() => {
93 | const range = new Range(new Point(8, 2), new Point(8, 8));
94 | editor.setSelectedBufferRange(range);
95 | advanceClock(20000);
96 | });
97 |
98 | it('adds the decoration to all words', () => {
99 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(4);
100 | });
101 |
102 | it('creates the highlight selected status bar element', () => {
103 | expect(workspaceElement.querySelector('status-bar')).toExist();
104 | expect(workspaceElement.querySelector('.highlight-selected-status')).toExist();
105 | });
106 |
107 | it('updates the status bar with highlights number', () => {
108 | const content = workspaceElement.querySelector('.highlight-selected-status').innerHTML;
109 | expect(content).toBe('Highlighted: 4');
110 | });
111 |
112 | describe('when the status bar is disabled', () => {
113 | beforeEach(() => atom.config.set('highlight-selected.showInStatusBar', false));
114 |
115 | it("highlight isn't attached", () => {
116 | expect(workspaceElement.querySelector('status-bar')).toExist();
117 | expect(workspaceElement.querySelector('.highlight-selected-status')).not.toExist();
118 | });
119 | });
120 | });
121 |
122 | describe('when hide highlight on selected word is enabled', () => {
123 | beforeEach(() => atom.config.set('highlight-selected.hideHighlightOnSelectedWord', true));
124 |
125 | describe('when a single line is selected', () => {
126 | beforeEach(() => {
127 | const range = new Range(new Point(8, 2), new Point(8, 8));
128 | editor.setSelectedBufferRange(range);
129 | advanceClock(20000);
130 | });
131 |
132 | it('adds the decoration only on selected words', () => {
133 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(3);
134 | });
135 | });
136 |
137 | describe('when multi lines are selected', () => {
138 | beforeEach(() => {
139 | const range1 = new Range(new Point(8, 2), new Point(8, 8));
140 | const range2 = new Range(new Point(9, 2), new Point(9, 8));
141 | editor.setSelectedBufferRanges([range1, range2]);
142 | advanceClock(20000);
143 | });
144 |
145 | it('adds the decoration only on selected words', () => {
146 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(2);
147 | });
148 | });
149 | });
150 |
151 | describe("leading whitespace doesn't get used", () => {
152 | beforeEach(() => {
153 | const range = new Range(new Point(8, 0), new Point(8, 8));
154 | editor.setSelectedBufferRange(range);
155 | advanceClock(20000);
156 | });
157 |
158 | it("doesn't add regions", () => {
159 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0);
160 | });
161 | });
162 |
163 | describe('ignores whitespace only selections', () => {
164 | beforeEach(() => atom.config.set('highlight-selected.onlyHighlightWholeWords', false));
165 |
166 | it('ignores space only selections', () => {
167 | const range = new Range(new Point(8, 0), new Point(8, 2));
168 | editor.setSelectedBufferRange(range);
169 | advanceClock(20000);
170 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0);
171 | });
172 |
173 | it('allows selections to include whitespace', () => {
174 | const range = new Range(new Point(8, 0), new Point(8, 8));
175 | editor.setSelectedBufferRange(range);
176 | advanceClock(20000);
177 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(3);
178 | });
179 | });
180 |
181 | describe('ignores selections that contain a new line', () => {
182 | beforeEach(() => atom.config.set('highlight-selected.onlyHighlightWholeWords', false));
183 |
184 | it('ignores a selection of a single newline', () => {
185 | const range = new Range(new Point(7, 14), new Point(8, 0)); // '\n'
186 | editor.setSelectedBufferRange(range);
187 | advanceClock(20000);
188 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0);
189 | });
190 |
191 | it('ignores any selection containing a newline', () => {
192 | const range = new Range(new Point(7, 14), new Point(8, 8)); // '\n string'
193 | editor.setSelectedBufferRange(range);
194 | advanceClock(20000);
195 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0);
196 | });
197 | });
198 |
199 | describe('will highlight non whole words', () => {
200 | beforeEach(() => {
201 | atom.config.set('highlight-selected.onlyHighlightWholeWords', false);
202 | const range = new Range(new Point(10, 13), new Point(10, 17));
203 | editor.setSelectedBufferRange(range);
204 | advanceClock(20000);
205 | });
206 |
207 | it('does add regions', () => {
208 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(3);
209 | });
210 | });
211 |
212 | describe('will not highlight non whole words', () => {
213 | beforeEach(() => {
214 | atom.config.set('highlight-selected.onlyHighlightWholeWords', true);
215 | const range = new Range(new Point(10, 13), new Point(10, 17));
216 | editor.setSelectedBufferRange(range);
217 | advanceClock(20000);
218 | });
219 |
220 | it('does add regions', () => {
221 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(2);
222 | });
223 | });
224 |
225 | describe('will not highlight less than minimum length', () => {
226 | beforeEach(() => {
227 | atom.config.set('highlight-selected.minimumLength', 7);
228 | const range = new Range(new Point(4, 0), new Point(4, 6));
229 | editor.setSelectedBufferRange(range);
230 | advanceClock(20000);
231 | });
232 |
233 | it("doesn't add regions", () =>
234 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0));
235 | });
236 |
237 | describe('will not highlight words in different case', () => {
238 | beforeEach(() => {
239 | const range = new Range(new Point(4, 0), new Point(4, 6));
240 | editor.setSelectedBufferRange(range);
241 | advanceClock(20000);
242 | });
243 |
244 | it('does add regions', () => {
245 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(2);
246 | });
247 | });
248 |
249 | describe('will highlight words in different case', () => {
250 | beforeEach(() => {
251 | atom.config.set('highlight-selected.ignoreCase', true);
252 | const range = new Range(new Point(4, 0), new Point(4, 6));
253 | editor.setSelectedBufferRange(range);
254 | advanceClock(20000);
255 | });
256 |
257 | it('does add regions', () => {
258 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(5);
259 | });
260 |
261 | describe('adds background to selected', () => {
262 | beforeEach(() => {
263 | atom.config.set('highlight-selected.highlightBackground', true);
264 | const range = new Range(new Point(8, 2), new Point(8, 8));
265 | editor.setSelectedBufferRange(range);
266 | advanceClock(20000);
267 | });
268 |
269 | it('adds the background to all highlights', () => {
270 | expect(
271 | editorElement.querySelectorAll('.highlight-selected.background .region')
272 | ).toHaveLength(4);
273 | });
274 | });
275 |
276 | describe('adds light theme to selected', () => {
277 | beforeEach(() => {
278 | atom.config.set('highlight-selected.lightTheme', true);
279 | const range = new Range(new Point(8, 2), new Point(8, 8));
280 | editor.setSelectedBufferRange(range);
281 | advanceClock(20000);
282 | });
283 |
284 | it('adds the background to all highlights', () =>
285 | expect(
286 | editorElement.querySelectorAll('.highlight-selected.light-theme .region')
287 | ).toHaveLength(4));
288 | });
289 | });
290 |
291 | if (hasMinimap) {
292 | describe('minimap highlight selected still works', () => {
293 | beforeEach(() => {
294 | editor = atom.workspace.getActiveTextEditor();
295 | minimap = minimapModule.minimapForEditor(editor);
296 |
297 | spyOn(minimap, 'decorateMarker').andCallThrough();
298 | const range = new Range(new Point(8, 2), new Point(8, 8));
299 | editor.setSelectedBufferRange(range);
300 | advanceClock(20000);
301 | });
302 |
303 | it('adds a decoration for the selection in the minimap', () => {
304 | expect(minimap.decorateMarker).toHaveBeenCalled();
305 | });
306 | });
307 | }
308 | });
309 |
310 | describe('when opening a php file', () => {
311 | beforeEach(() => {
312 | waitsForPromise(() =>
313 | atom.packages.activatePackage('highlight-selected').then(({ mainModule }) => {
314 | highlightSelected = mainModule;
315 | })
316 | );
317 |
318 | waitsForPromise(() =>
319 | atom.workspace.open('sample.php').then(
320 | () => editor,
321 | (error) => {
322 | throw error.stack;
323 | }
324 | )
325 | );
326 |
327 | waitsForPromise(() => atom.packages.activatePackage('language-php'));
328 |
329 | runs(() => {
330 | jasmine.attachToDOM(workspaceElement);
331 | editor = atom.workspace.getActiveTextEditor();
332 | editorElement = atom.views.getView(editor);
333 | });
334 | });
335 |
336 | describe("being able to highlight variables with '$'", () => {
337 | beforeEach(() => {
338 | atom.config.set('highlight-selected.onlyHighlightWholeWords', true);
339 | const range = new Range(new Point(1, 2), new Point(1, 7));
340 | editor.setSelectedBufferRange(range);
341 | advanceClock(20000);
342 | });
343 |
344 | it('finds 3 regions', () => {
345 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(3);
346 | });
347 | });
348 |
349 | // describe("not being able to highlight variables when not selecting '$'", () => {
350 | // beforeEach(() => {
351 | // atom.config.set('highlight-selected.onlyHighlightWholeWords', true);
352 | // const range = new Range(new Point(1, 3), new Point(1, 7));
353 | // editor.setSelectedBufferRange(range);
354 | // advanceClock(20000);
355 | // });
356 |
357 | // it('finds 0 regions', () => {
358 | // expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(0);
359 | // });
360 | // });
361 |
362 | // describe("being able to highlight other strings when not selecting '@'", () => {
363 | // beforeEach(() => {
364 | // atom.config.set('highlight-selected.onlyHighlightWholeWords', true);
365 | // const range = new Range(new Point(3, 6), new Point(3, 10));
366 | // editor.setSelectedBufferRange(range);
367 | // advanceClock(20000);
368 | // });
369 |
370 | // it('finds 2 regions', () => {
371 | // expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(2);
372 | // });
373 | // });
374 | });
375 |
376 | describe('when opening a file with hex like data', () => {
377 | beforeEach(() => {
378 | waitsForPromise(() =>
379 | atom.packages.activatePackage('status-bar').then(() => {
380 | workspaceElement.querySelector('status-bar');
381 | })
382 | );
383 |
384 | waitsForPromise(() =>
385 | atom.packages.activatePackage('highlight-selected').then(({ mainModule }) => {
386 | highlightSelected = mainModule;
387 | })
388 | );
389 |
390 | if (hasMinimap) {
391 | waitsForPromise(() =>
392 | atom.packages.activatePackage('minimap').then(({ mainModule }) => {
393 | minimapModule = mainModule;
394 | })
395 | );
396 | waitsForPromise(() =>
397 | atom.packages.activatePackage('minimap-highlight-selected').then(({ mainModule }) => {
398 | minimapHS = mainModule;
399 | })
400 | );
401 | }
402 |
403 | waitsForPromise(() =>
404 | atom.workspace.open('hex.md').then(
405 | () => null,
406 | (error) => {
407 | throw error.stack;
408 | }
409 | )
410 | );
411 |
412 | runs(() => {
413 | jasmine.attachToDOM(workspaceElement);
414 | editor = atom.workspace.getActiveTextEditor();
415 | editorElement = atom.views.getView(editor);
416 | editorElement.setHeight(250);
417 | editorElement.component.measureDimensions();
418 | });
419 | });
420 |
421 | describe("being able to highlight the first '00000000'", () => {
422 | beforeEach(() => {
423 | const range = new Range(new Point(0, 0), new Point(0, 8));
424 | editor.setSelectedBufferRange(range);
425 | advanceClock(20000);
426 | });
427 |
428 | it('finds 18 regions', () => {
429 | expect(editorElement.querySelectorAll('.highlight-selected .region')).toHaveLength(18);
430 | });
431 | });
432 | });
433 |
434 | describe('when opening a big file', () => {
435 | beforeEach(() => {
436 | waitsForPromise(() =>
437 | atom.packages.activatePackage('status-bar').then(() => {
438 | workspaceElement.querySelector('status-bar');
439 | })
440 | );
441 |
442 | waitsForPromise(() =>
443 | atom.packages.activatePackage('highlight-selected').then(({ mainModule }) => {
444 | highlightSelected = mainModule;
445 | })
446 | );
447 |
448 | if (hasMinimap) {
449 | waitsForPromise(() =>
450 | atom.packages.activatePackage('minimap').then(({ mainModule }) => {
451 | minimapModule = mainModule;
452 | })
453 | );
454 | waitsForPromise(() =>
455 | atom.packages.activatePackage('minimap-highlight-selected').then(({ mainModule }) => {
456 | minimapHS = mainModule;
457 | })
458 | );
459 | }
460 |
461 | waitsForPromise(() =>
462 | atom.workspace.open().then(
463 | () => null,
464 | (error) => {
465 | throw error.stack;
466 | }
467 | )
468 | );
469 |
470 | runs(() => {
471 | jasmine.attachToDOM(workspaceElement);
472 | editor = atom.workspace.getActiveTextEditor();
473 | editor.setText('a'.repeat(40000));
474 | editorElement = atom.views.getView(editor);
475 | editorElement.setHeight(250);
476 | editorElement.component.measureDimensions();
477 | });
478 | });
479 |
480 | describe('when doing a big selection', () => {
481 | // see: https://github.com/richrace/highlight-selected/issues/206
482 | beforeEach(() => {
483 | const range = new Range(new Point(0, 3), new Point(0, 38000));
484 | editor.setSelectedBufferRange(range);
485 | advanceClock(20000);
486 | });
487 |
488 | it('updates the status bar with highlights number', () => {
489 | const content = workspaceElement.querySelector('.highlight-selected-status').innerHTML;
490 | expect(content).toBe('Highlighted: 0');
491 | });
492 |
493 | describe('when the status bar is disabled', () => {
494 | beforeEach(() => atom.config.set('highlight-selected.showInStatusBar', false));
495 |
496 | it("highlight isn't attached", () => {
497 | expect(workspaceElement.querySelector('status-bar')).toExist();
498 | expect(workspaceElement.querySelector('.highlight-selected-status')).not.toExist();
499 | });
500 | });
501 | });
502 | });
503 | });
504 |
--------------------------------------------------------------------------------
/Tests/main-spec.js:
--------------------------------------------------------------------------------
1 | const { CompositeDisposable } = require('atom');
2 | const main = require('../Source/App.js');
3 | const SelectionManager = require('../Source/selection-manager.js');
4 | const StatusBarService = require('../Source/status-bar/status-bar-service.js');
5 | const ScrollMarkersService = require('../Source/scroll-markers/scroll-markers-service.js');
6 |
7 | describe('Main', () => {
8 |
9 | describe('active', () => {
10 | it('creates a SelectionManager', () => {
11 | main.activate();
12 | expect(main.selectionManager instanceof SelectionManager).toBe(true);
13 | });
14 |
15 | it('will listen to commands', () => {
16 | spyOn(main, 'listenForCommands').andCallThrough();
17 | main.activate();
18 | expect(main.listenForCommands).toHaveBeenCalled();
19 | });
20 |
21 | it('has subscriptions that is a CompositeDisposable', () => {
22 | main.activate();
23 | expect(main.subscriptions instanceof CompositeDisposable).toBe(true);
24 | });
25 | });
26 |
27 | describe('deactivate', () => {
28 | it('destroys the selection manager and sets it to null', () => {
29 | const selectionManager = jasmine.createSpyObj('SelectionManager', ['destroy']);
30 | main.selectionManager = selectionManager;
31 | main.deactivate();
32 | expect(selectionManager.destroy).toHaveBeenCalled();
33 | expect(main.selectionManager).toBeNull();
34 | });
35 |
36 | it('disposes of the subscriptions and sets it to null', () => {
37 | const subscriptions = jasmine.createSpyObj('subscriptions', ['dispose']);
38 | main.subscriptions = subscriptions;
39 | main.deactivate();
40 | expect(subscriptions.dispose).toHaveBeenCalled();
41 | expect(main.subscriptions).toBeNull();
42 | });
43 |
44 | it('destroys the scrollMarkersService and sets it to null', () => {
45 | const scrollMarkersService = jasmine.createSpyObj('scrollMarkersService', ['destroy']);
46 | main.scrollMarkersService = scrollMarkersService;
47 | main.deactivate();
48 | expect(scrollMarkersService.destroy).toHaveBeenCalled();
49 | expect(main.scrollMarkersService).toBeNull();
50 | });
51 |
52 | it('destroys the statusBarService and sets it to null', () => {
53 | const statusBarService = jasmine.createSpyObj('statusBarService', ['destroy']);
54 | main.statusBarService = statusBarService;
55 | main.deactivate();
56 | expect(statusBarService.destroy).toHaveBeenCalled();
57 | expect(main.statusBarService).toBeNull();
58 | });
59 | });
60 |
61 | describe('consumeStatusBar', () => {
62 | let statusBar;
63 | let selectionManager;
64 |
65 | beforeEach(() => {
66 | statusBar = {};
67 | selectionManager = {
68 | onDidFinishAddingMarkers: () => {},
69 | onDidRemoveAllMarkers: () => {},
70 | };
71 | main.selectionManager = selectionManager;
72 | main.consumeStatusBar(statusBar);
73 | });
74 |
75 | it('creates a StatusBarService', () => {
76 | expect(main.statusBarService instanceof StatusBarService).toBe(true);
77 | });
78 |
79 | it('assings selection manager correctly', () => {
80 | expect(main.statusBarService.selectionManager).toBe(selectionManager);
81 | });
82 |
83 | it('assings status bar object correctly', () => {
84 | expect(main.statusBarService.statusBar).toBe(statusBar);
85 | });
86 | });
87 |
88 | describe('toggle', () => {
89 | let selectionManager;
90 |
91 | describe('when selection manager is disabled', () => {
92 | beforeEach(() => {
93 | selectionManager = {
94 | disabled: true,
95 | enable: () => {},
96 | disable: () => {},
97 | };
98 |
99 | spyOn(selectionManager, 'enable');
100 | spyOn(selectionManager, 'disable');
101 | main.selectionManager = selectionManager;
102 | });
103 |
104 | it('enables the selection manager', () => {
105 | main.toggle();
106 | expect(selectionManager.enable).toHaveBeenCalled();
107 | expect(selectionManager.disable).not.toHaveBeenCalled();
108 | });
109 | });
110 |
111 | describe('when selection manager is enabled', () => {
112 | beforeEach(() => {
113 | selectionManager = {
114 | disabled: false,
115 | enable: () => {},
116 | disable: () => {},
117 | };
118 |
119 | spyOn(selectionManager, 'enable');
120 | spyOn(selectionManager, 'disable');
121 | main.selectionManager = selectionManager;
122 | });
123 |
124 | it('disables the selection manager', () => {
125 | main.toggle();
126 | expect(selectionManager.enable).not.toHaveBeenCalled();
127 | expect(selectionManager.disable).toHaveBeenCalled();
128 | });
129 | });
130 | });
131 |
132 | describe('selectAll', () => {
133 | it('calls selectAll on selectionMananger', () => {
134 | const selectionManager = jasmine.createSpyObj('selectionManager', ['selectAll']);
135 | main.selectionManager = selectionManager;
136 | main.selectAll();
137 | expect(selectionManager.selectAll).toHaveBeenCalled();
138 | });
139 | });
140 |
141 | describe('consumeScrollMarker', () => {
142 | let scrollMarkerAPI;
143 | let selectionManager;
144 |
145 | beforeEach(() => {
146 | scrollMarkerAPI = {};
147 | selectionManager = {
148 | onDidFinishAddingMarkers: () => {},
149 | onDidRemoveAllMarkers: () => {},
150 | };
151 | main.scrollMarkersService = new ScrollMarkersService(selectionManager);
152 | main.selectionManager = selectionManager;
153 | main.consumeScrollMarker(scrollMarkerAPI);
154 | });
155 |
156 | it('creates a ScrollMarkersService', () => {
157 | expect(main.scrollMarkersService instanceof ScrollMarkersService).toBe(true);
158 | });
159 |
160 | it('assings selection manager correctly', () => {
161 | expect(main.scrollMarkersService.selectionManager).toBe(selectionManager);
162 | });
163 |
164 | it('assings status bar object correctly', () => {
165 | expect(main.scrollMarkersService.api).toBe(scrollMarkerAPI);
166 | });
167 | });
168 |
169 | describe('listenForCommands', () => {
170 | beforeEach(() => {
171 | main.listenForCommands();
172 | });
173 |
174 | it('adds a toggle command', () => {
175 | expect(atom.commands.registeredCommands['highlight-selected:toggle']).toBe(true);
176 | });
177 |
178 | it('and select all commands', () => {
179 | expect(atom.commands.registeredCommands['highlight-selected:select-all']).toBe(true);
180 | });
181 | });
182 | });
183 |
--------------------------------------------------------------------------------
/Tests/scroll-markers/scroll-markers-service-spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const ScrollMarkersService = require('../../Source/scroll-markers/scroll-markers-service');
3 |
4 | describe('ScrollMarkersService', () => {
5 | let scrollMarkersService;
6 | let selectionManager;
7 | let scrollMarkerApi;
8 |
9 | const createScrollMarkersService = () => {
10 | selectionManager = {
11 | onDidFinishAddingMarkers: () => {},
12 | onDidRemoveAllMarkers: () => {},
13 | };
14 | spyOn(selectionManager, 'onDidFinishAddingMarkers');
15 | spyOn(selectionManager, 'onDidRemoveAllMarkers');
16 | scrollMarkerApi = {};
17 | scrollMarkersService = new ScrollMarkersService(selectionManager);
18 | scrollMarkersService.setScrollMarkerAPI(scrollMarkerApi);
19 | };
20 |
21 | beforeEach(() => {
22 | waitsForPromise(() => atom.packages.activatePackage('highlight-selected'));
23 | atom.config.set('highlight-selected.showResultsOnScrollBar', true);
24 | });
25 |
26 | describe('constructor', () => {
27 | describe('when show results on scroll bar is enabled', () => {
28 | beforeEach(() => {
29 | atom.config.set('highlight-selected.showResultsOnScrollBar', true);
30 | });
31 |
32 | it('ensures we have scroll marker package installed', () => {
33 | spyOn(ScrollMarkersService, 'ensureScrollViewInstalled');
34 | createScrollMarkersService();
35 | expect(ScrollMarkersService.ensureScrollViewInstalled).toHaveBeenCalled();
36 | });
37 | });
38 | });
39 |
40 | describe('destroyScrollMarkers', () => {
41 | beforeEach(() => {
42 | createScrollMarkersService();
43 | });
44 |
45 | describe('when there is no scroll marker API', () => {
46 | it('does not blow up', () => {
47 | scrollMarkersService.api = null;
48 | scrollMarkersService.destroyScrollMarkers();
49 | });
50 | });
51 |
52 | it('destroys the marker view from the scroll bar API', () => {
53 | const editor = {};
54 | const markerView = { destroy: () => {} };
55 | scrollMarkerApi.scrollMarkerViewForEditor = () => markerView;
56 | spyOn(scrollMarkerApi, 'scrollMarkerViewForEditor').andCallThrough();
57 | spyOn(markerView, 'destroy');
58 |
59 | scrollMarkersService.destroyScrollMarkers(editor);
60 | expect(scrollMarkerApi.scrollMarkerViewForEditor).toHaveBeenCalledWith(editor);
61 | expect(markerView.destroy).toHaveBeenCalled();
62 | });
63 | });
64 |
65 | describe('setScrollMarkerView', () => {
66 | const editor = { id: 9999 };
67 | const layer = { syncToMarkerLayer: () => {} };
68 | const markerView = { getLayer: () => layer };
69 | const visibleMarkerLayer = {};
70 | const selectedMarkerLayer = {};
71 |
72 | beforeEach(() => {
73 | createScrollMarkersService();
74 | scrollMarkerApi.scrollMarkerViewForEditor = () => markerView;
75 | selectionManager.editorToMarkerLayerMap = {};
76 | selectionManager.editorToMarkerLayerMap[editor.id] = {
77 | visibleMarkerLayer,
78 | selectedMarkerLayer,
79 | };
80 | });
81 |
82 | describe('when show results on scroll bar is disabled', () => {
83 | beforeEach(() => {
84 | atom.config.set('highlight-selected.showResultsOnScrollBar', false);
85 | });
86 |
87 | it('does not use the api', () => {
88 | scrollMarkerApi.scrollMarkerViewForEditor = () => {};
89 | spyOn(scrollMarkerApi, 'scrollMarkerViewForEditor');
90 | scrollMarkersService.setScrollMarkerView();
91 | expect(scrollMarkerApi.scrollMarkerViewForEditor).not.toHaveBeenCalled();
92 | });
93 | });
94 |
95 | describe('when the scroll marker API is not set', () => {
96 | it('does not blow up', () => {
97 | scrollMarkersService.api = null;
98 | expect(scrollMarkersService.setScrollMarkerView()).toBeUndefined();
99 | });
100 | });
101 |
102 | it('gets the scroll marker view for the editor', () => {
103 | spyOn(scrollMarkerApi, 'scrollMarkerViewForEditor').andCallThrough();
104 |
105 | scrollMarkersService.setScrollMarkerView(editor);
106 | expect(scrollMarkerApi.scrollMarkerViewForEditor).toHaveBeenCalledWith(editor);
107 | });
108 |
109 | it('syncs the visibleMarkerLayer from selection manager to the scroll marker api', () => {
110 | spyOn(markerView, 'getLayer').andCallThrough();
111 | spyOn(layer, 'syncToMarkerLayer');
112 |
113 | scrollMarkersService.setScrollMarkerView(editor);
114 |
115 | expect(markerView.getLayer).toHaveBeenCalledWith('highlight-selected-marker-layer');
116 | expect(layer.syncToMarkerLayer).toHaveBeenCalledWith(visibleMarkerLayer);
117 | });
118 |
119 | it('syncs the selectedMarkerLayer from selection manager to the scroll marker api', () => {
120 | spyOn(markerView, 'getLayer').andCallThrough();
121 | spyOn(layer, 'syncToMarkerLayer');
122 |
123 | scrollMarkersService.setScrollMarkerView(editor);
124 |
125 | expect(markerView.getLayer).toHaveBeenCalledWith('highlight-selected-selected-marker-layer');
126 | expect(layer.syncToMarkerLayer).toHaveBeenCalledWith(selectedMarkerLayer);
127 | });
128 | });
129 |
130 | describe('setupConfigObserver', () => {
131 | beforeEach(() => {
132 | createScrollMarkersService();
133 | });
134 |
135 | describe('when enabling show results on scroll bar', () => {
136 | beforeEach(() => {
137 | atom.config.set('highlight-selected.showResultsOnScrollBar', false);
138 | });
139 |
140 | it('ensures the scroll bar package is installed', () => {
141 | spyOn(ScrollMarkersService, 'ensureScrollViewInstalled');
142 | atom.config.set('highlight-selected.showResultsOnScrollBar', true);
143 |
144 | expect(ScrollMarkersService.ensureScrollViewInstalled).toHaveBeenCalled();
145 | });
146 |
147 | it('sets scroll marker view for any open editor', () => {
148 | atom.project.setPaths([path.join(__dirname, 'fixtures')]);
149 | waitsForPromise(() => atom.workspace.open('sample.php'));
150 |
151 | runs(() => {
152 | const editor = atom.workspace.getActiveTextEditor();
153 | spyOn(scrollMarkersService, 'setScrollMarkerView');
154 | atom.config.set('highlight-selected.showResultsOnScrollBar', true);
155 | expect(scrollMarkersService.setScrollMarkerView).toHaveBeenCalledWith(editor);
156 | });
157 | });
158 | });
159 |
160 | describe('when disabling show results on scroll bar', () => {
161 | beforeEach(() => {
162 | atom.config.set('highlight-selected.showResultsOnScrollBar', true);
163 | // Turn off the editor subscriptions otherwise everything breaks as we have stubbed out the
164 | // Scroll Marker API. We do not want to actually run the thing.
165 | scrollMarkersService.editorSubscriptions.dispose();
166 | });
167 |
168 | it('destroys scroll markers for open editors', () => {
169 | atom.project.setPaths([path.join(__dirname, 'fixtures')]);
170 | waitsForPromise(() => atom.workspace.open('sample.php'));
171 |
172 | runs(() => {
173 | const editor = atom.workspace.getActiveTextEditor();
174 | spyOn(scrollMarkersService, 'destroyScrollMarkers');
175 | atom.config.set('highlight-selected.showResultsOnScrollBar', false);
176 | expect(scrollMarkersService.destroyScrollMarkers).toHaveBeenCalledWith(editor);
177 | });
178 | });
179 | });
180 | });
181 | });
182 |
--------------------------------------------------------------------------------
/Tests/status-bar/status-bar-service-spec.js:
--------------------------------------------------------------------------------
1 | const StatusBarService = require('../../Source/status-bar/status-bar-service');
2 |
3 | describe('StatusBarService', () => {
4 | let statusBarService;
5 | let selectionManager;
6 | let statusBarApi;
7 | const tile = { destroy: () => {} };
8 |
9 | const createStatusBarService = () => {
10 | statusBarApi = {
11 | addLeftTile: () => tile,
12 | };
13 | spyOn(statusBarApi, 'addLeftTile').andCallThrough();
14 | selectionManager = {
15 | onDidFinishAddingMarkers: () => {},
16 | onDidRemoveAllMarkers: () => {},
17 | };
18 | spyOn(selectionManager, 'onDidFinishAddingMarkers');
19 | spyOn(selectionManager, 'onDidRemoveAllMarkers');
20 | statusBarService = new StatusBarService(statusBarApi, selectionManager);
21 | };
22 |
23 | beforeEach(() => {
24 | waitsForPromise(() => atom.packages.activatePackage('highlight-selected'));
25 | waitsForPromise(() => atom.packages.activatePackage('status-bar'));
26 | });
27 |
28 | it('listens for once all markers are added', () => {
29 | createStatusBarService();
30 | expect(selectionManager.onDidFinishAddingMarkers).toHaveBeenCalled();
31 | });
32 |
33 | it('listens for for when all markers have been removed', () => {
34 | createStatusBarService();
35 | expect(selectionManager.onDidRemoveAllMarkers).toHaveBeenCalled();
36 | });
37 |
38 | describe('destroy', () => {
39 | let selectionSubscriptionSpy;
40 |
41 | beforeEach(() => {
42 | createStatusBarService();
43 | selectionSubscriptionSpy = {
44 | dispose: () => {},
45 | };
46 | spyOn(selectionSubscriptionSpy, 'dispose');
47 | statusBarService.selectionSubscription = selectionSubscriptionSpy;
48 | spyOn(statusBarService, 'removeStatusBarView');
49 | });
50 |
51 | it('removes subscriptions', () => {
52 | statusBarService.destroy();
53 | expect(selectionSubscriptionSpy.dispose).toHaveBeenCalled();
54 | });
55 |
56 | it('removes status bar', () => {
57 | statusBarService.destroy();
58 | expect(statusBarService.removeStatusBarView).toHaveBeenCalled();
59 | });
60 | });
61 |
62 | describe('listenForStatusBarConfigChange', () => {
63 | beforeEach(() => {
64 | createStatusBarService();
65 | });
66 |
67 | describe('when it is enabled', () => {
68 | beforeEach(() => {
69 | atom.config.set('highlight-selected.showInStatusBar', true);
70 | const selectionSubscriptionSpy = {
71 | dispose: () => {},
72 | };
73 | spyOn(selectionSubscriptionSpy, 'dispose');
74 | statusBarService.selectionSubscription = selectionSubscriptionSpy;
75 | });
76 |
77 | it('calls removeStatusBarView when set to false', () => {
78 | spyOn(statusBarService, 'removeStatusBarView');
79 | atom.config.set('highlight-selected.showInStatusBar', false);
80 | expect(statusBarService.removeStatusBarView).toHaveBeenCalled();
81 | });
82 | });
83 |
84 | describe('when it is disabled', () => {
85 | beforeEach(() => {
86 | spyOn(statusBarService, 'removeStatusBarView');
87 | atom.config.set('highlight-selected.showInStatusBar', false);
88 | });
89 |
90 | it('calls setupStatusBarView when set to true', () => {
91 | spyOn(statusBarService, 'setupStatusBarView');
92 | atom.config.set('highlight-selected.showInStatusBar', true);
93 | expect(statusBarService.setupStatusBarView).toHaveBeenCalled();
94 | });
95 | });
96 | });
97 |
98 | describe('setupStatusBarView', () => {
99 | describe('when we already have an element setup', () => {
100 | const element = {
101 | temp: 'Object',
102 | };
103 |
104 | beforeEach(() => {
105 | createStatusBarService();
106 | statusBarService.statusBarElement = element;
107 | });
108 |
109 | it('does not overwrite element', () => {
110 | statusBarService.setupStatusBarView();
111 | expect(statusBarService.statusBarElement).toBe(element);
112 | });
113 | });
114 |
115 | describe('when we have not enabled the status bar', () => {
116 | beforeEach(() => {
117 | atom.config.set('highlight-selected.showInStatusBar', false);
118 | createStatusBarService();
119 | });
120 |
121 | it('does not have an element', () => {
122 | expect(statusBarService.statusBarElement).toBeUndefined();
123 | });
124 | });
125 |
126 | describe('when we have enabled the status bar', () => {
127 | beforeEach(() => {
128 | atom.config.set('highlight-selected.showInStatusBar', true);
129 | createStatusBarService();
130 | });
131 |
132 | it('adds the status bar to the left hand side', () => {
133 | expect(statusBarApi.addLeftTile).toHaveBeenCalledWith({
134 | item: statusBarService.statusBarElement.element ,
135 | priority: 100,
136 | });
137 | });
138 | });
139 | });
140 |
141 | describe('removeStatusBarView', () => {
142 | beforeEach(() => {
143 | atom.config.set('highlight-selected.showInStatusBar', true);
144 | createStatusBarService();
145 | });
146 |
147 | describe('when there is not an element', () => {
148 | beforeEach(() => {
149 | statusBarService.statusBarElement = null;
150 | });
151 |
152 | it('does not destroy the tile', () => {
153 | spyOn(tile, 'destroy');
154 | statusBarService.removeStatusBarView();
155 | expect(tile.destroy).not.toHaveBeenCalled();
156 | });
157 | });
158 |
159 | describe('when there is an element', () => {
160 | let statusBarElement;
161 |
162 | beforeEach(() => {
163 | ({ statusBarElement } = statusBarService);
164 | spyOn(statusBarElement, 'removeElement');
165 | });
166 |
167 | it('removes the element', () => {
168 | statusBarService.removeStatusBarView();
169 | expect(statusBarElement.removeElement).toHaveBeenCalled();
170 | });
171 |
172 | it('destroys the tile', () => {
173 | spyOn(tile, 'destroy');
174 | statusBarService.removeStatusBarView();
175 | expect(tile.destroy).toHaveBeenCalled();
176 | });
177 |
178 | it('sets the tile to be null', () => {
179 | expect(statusBarService.statusBarTile).not.toBeNull();
180 | statusBarService.removeStatusBarView();
181 | expect(statusBarService.statusBarTile).toBeNull();
182 | });
183 |
184 | it('sets the element to be null', () => {
185 | expect(statusBarService.statusBarElement).not.toBeNull();
186 | statusBarService.removeStatusBarView();
187 | expect(statusBarService.statusBarElement).toBeNull();
188 | });
189 | });
190 | });
191 |
192 | describe('updateCount', () => {
193 | beforeEach(() => {
194 | createStatusBarService();
195 | });
196 |
197 | describe('when there is no element', () => {
198 | beforeEach(() => {
199 | statusBarService.statusBarElement = null;
200 | });
201 |
202 | it('does not error', () => {
203 | statusBarService.updateCount();
204 | });
205 | });
206 |
207 | it('calls the updateCount function on the element', () => {
208 | const { statusBarElement } = statusBarService;
209 | spyOn(statusBarElement, 'updateCount');
210 | statusBarService.updateCount();
211 | expect(statusBarElement.updateCount).toHaveBeenCalled();
212 | });
213 |
214 | it("uses the selection manager's resultCount", () => {
215 | const number = 123;
216 | selectionManager.resultCount = number;
217 | const { statusBarElement } = statusBarService;
218 | spyOn(statusBarElement, 'updateCount');
219 | statusBarService.updateCount();
220 | expect(statusBarElement.updateCount).toHaveBeenCalledWith(number);
221 | });
222 | });
223 | });
224 |
--------------------------------------------------------------------------------
/Tests/status-bar/status-bar-view-spec.js:
--------------------------------------------------------------------------------
1 | const StatusBarView = require('../../Source/status-bar/status-bar-view');
2 |
3 | describe('StatusBarView', () => {
4 | let statusBarView;
5 |
6 | beforeEach(() => {
7 | waitsForPromise(() => atom.packages.activatePackage('highlight-selected'));
8 | statusBarView = new StatusBarView();
9 | });
10 |
11 | it('creates a div element', () => {
12 | expect(statusBarView.element.tagName).toBe('DIV');
13 | });
14 |
15 | it('div contains correct classes', () => {
16 | expect(statusBarView.element).toHaveClass('highlight-selected-status');
17 | expect(statusBarView.element).toHaveClass('inline-block');
18 | });
19 |
20 | it('returns element', () => {
21 | expect(statusBarView.element).toBe(statusBarView.element);
22 | });
23 |
24 | describe('updateCount', () => {
25 | it('updates with 0', () => {
26 | const expectedText = 'Highlighted: 0';
27 | statusBarView.updateCount(0);
28 | expect(statusBarView.element).toHaveClass('highlight-selected-hidden');
29 | expect(statusBarView.element).toHaveText(expectedText);
30 | });
31 |
32 | it('updates with 1', () => {
33 | const expectedText = 'Highlighted: 1';
34 | statusBarView.updateCount(1);
35 | expect(statusBarView.element).not.toHaveClass('highlight-selected-hidden');
36 | expect(statusBarView.element).toHaveText(expectedText);
37 | });
38 |
39 | it('updates with 55', () => {
40 | const expectedText = 'Highlighted: 55';
41 | statusBarView.updateCount(55);
42 | expect(statusBarView.element).not.toHaveClass('highlight-selected-hidden');
43 | expect(statusBarView.element).toHaveText(expectedText);
44 | });
45 | });
46 |
47 | it('removes the element from the parent', () => {
48 | const parentNode = { removeChild: () => {} };
49 | const element = { parentNode };
50 |
51 | spyOn(parentNode, 'removeChild');
52 |
53 | statusBarView.element = element;
54 | statusBarView.removeElement();
55 |
56 | expect(parentNode.removeChild).toHaveBeenCalledWith(element);
57 | expect(statusBarView.element).toBeNull();
58 | });
59 | });
60 |
--------------------------------------------------------------------------------
/Tests/utils/non-word-characters-spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const getNonWordCharacters = require('../../Source/utils/non-word-characters.js');
3 |
4 | describe('with a CoffeeScript file', () => {
5 | const nonWordCharacters = '{}[]<>';
6 | let workspaceElement;
7 | let editor;
8 | let selectionStart;
9 |
10 | beforeEach(() => {
11 | // Need this package to be active otherwise we do not use the source in the
12 | // `getNonWordCharacters` function
13 | waitsForPromise(() => atom.packages.activatePackage('language-coffee-script'));
14 |
15 | atom.config.set('editor.nonWordCharacters', nonWordCharacters, {
16 | scopeSelector: '.source.coffee',
17 | });
18 |
19 | workspaceElement = atom.views.getView(atom.workspace);
20 | atom.project.setPaths([path.join('..', '..', 'fixtures')]);
21 |
22 | waitsForPromise(() => atom.workspace.open('sample.coffee'));
23 |
24 | runs(() => {
25 | jasmine.attachToDOM(workspaceElement);
26 | editor = atom.workspace.getActiveTextEditor();
27 | const editorElement = atom.views.getView(editor);
28 | editorElement.setHeight(250);
29 | editorElement.component.measureDimensions();
30 | selectionStart = editor.getLastSelection().getBufferRange().start;
31 | });
32 | });
33 |
34 | it('returns differently than the editor.nonWordCharacters', () => {
35 | expect(getNonWordCharacters(editor, selectionStart)).not.toBe(
36 | atom.config.get('editor.nonWordCharacters')
37 | );
38 | });
39 |
40 | it('returns the correct non word characters', () => {
41 | expect(getNonWordCharacters(editor, selectionStart)).toBe(nonWordCharacters);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "description" : "Highlights the current word selected when double clicking" ,
3 | "version" : "1.0.0" ,
4 | "license" : "MIT" ,
5 | "name" : "highlight-selected" ,
6 |
7 | "keywords" : [ "highlight" , "select" , "occurrence" , "mark" ] ,
8 |
9 | "homepage" : "https://github.com/Pulsar-Edit-Highlights/selected" ,
10 |
11 | "repository" : {
12 | "type" : "git" ,
13 | "url" : "https://github.com/Pulsar-Edit-Highlights/selected"
14 | },
15 |
16 | "bugs" : {
17 | "url" : "https://github.com/Pulsar-Edit-Highlights/selected/issues"
18 | },
19 |
20 | "mainStyleSheet" : "./Resources/Stylesheet.less" ,
21 | "main" : "./Source/App.js" ,
22 |
23 | "keymaps" : [ "../Resources/Keymap.json" ] ,
24 | "menus" : [ "../Resources/Menus.json" ] ,
25 |
26 | "engines" : {
27 | "pulsar" : ">=1.100.0 <2.0.0"
28 | },
29 |
30 | "scripts" : {
31 | "test" : "pulsar --test Tests"
32 | },
33 |
34 | "dependencies" : {
35 | "atom-package-deps" : "^7.0.0" ,
36 | "debounce" : "^1.2.0" ,
37 | "grim" : "^2.0.2"
38 | },
39 |
40 |
41 | "providedServices" : {
42 | "highlightSelected" : {
43 |
44 | "description" : "Exposes Highlight Selected Events" ,
45 |
46 | "versions" : {
47 | "1.0.0" : "provideHighlightSelectedV1Deprecated" ,
48 | "2.0.0" : "provideHighlightSelectedV2"
49 | }
50 | }
51 | },
52 |
53 | "consumedServices" : {
54 |
55 | "status-bar" : {
56 | "versions" : {
57 | "^1.0.0" : "consumeStatusBar"
58 | }
59 | },
60 |
61 | "scroll-marker" : {
62 | "versions" : {
63 | "0.1.0" : "consumeScrollMarker"
64 | }
65 | }
66 | },
67 |
68 | "package-deps" : [{ "name" : "scroll-marker" }],
69 |
70 | "configSchema" : {
71 |
72 | "onlyHighlightWholeWords" : {
73 | "default" : true ,
74 | "type" : "boolean"
75 | },
76 |
77 | "hideHighlightOnSelectedWord" : {
78 | "default" : false ,
79 | "type" : "boolean"
80 | },
81 |
82 | "ignoreCase" : {
83 | "default" : false ,
84 | "type" : "boolean"
85 | },
86 |
87 | "lightTheme" : {
88 | "default" : false ,
89 | "type" : "boolean"
90 | },
91 |
92 | "highlightBackground" : {
93 | "default" : false ,
94 | "type" : "boolean"
95 | },
96 |
97 | "minimumLength" : {
98 | "default" : 2 ,
99 | "type" : "integer"
100 | },
101 |
102 | "maximumHighlights" : {
103 | "description" : "For performance purposes, the number of highlights is limited." ,
104 | "default" : 500 ,
105 | "type" : "integer"
106 | },
107 |
108 | "timeout" : {
109 | "description" : "Defers searching for matching strings for X ms." ,
110 | "default" : 20 ,
111 | "type" : "integer"
112 | },
113 |
114 | "showInStatusBar" : {
115 | "description" : "Show how many matches there are." ,
116 | "default" : true ,
117 | "type" : "boolean"
118 | },
119 |
120 | "highlightInPanes" : {
121 | "description" : "Highlight selection in another panes." ,
122 | "default" : true ,
123 | "type" : "boolean"
124 | },
125 |
126 | "statusBarString" : {
127 | "description" : "The text to show in the status bar. %c = number of occurrences." ,
128 | "default" : "Highlighted: %c" ,
129 | "type" : "string"
130 | },
131 |
132 | "allowedCharactersToSelect" : {
133 | "description" : "Non Word Characters that are allowed to be selected." ,
134 | "default" : "$@%-" ,
135 | "type" : "string"
136 | },
137 |
138 | "showResultsOnScrollBar" : {
139 | "description" : "Show highlight on the scroll bar." ,
140 | "default" : false ,
141 | "type" : "boolean"
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------