├── .appcast.xml
├── .gitignore
├── Autocomplete.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDETemplateMacros.plist
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── Autocomplete.xcscheme
├── Autocomplete
├── Autocomplete.h
├── Info.plist
└── Sources
│ ├── Categories
│ ├── NSColor+Autocomplete.h
│ ├── NSColor+Autocomplete.m
│ ├── NSView+Autocomplete.h
│ └── NSView+Autocomplete.m
│ ├── Controllers
│ ├── ZPLEmojiController.h
│ ├── ZPLEmojiController.m
│ ├── ZPLSuggestionController.h
│ ├── ZPLSuggestionController.m
│ ├── ZPLSuggestionWindowController.h
│ └── ZPLSuggestionWindowController.m
│ ├── Models
│ ├── Sketch
│ │ └── ZPLTheme.h
│ ├── ZPLEmoji.h
│ ├── ZPLEmoji.m
│ ├── ZPLSuggestion.h
│ └── ZPLSuggestion.m
│ ├── Views
│ ├── ZPLFocusTableView.h
│ ├── ZPLFocusTableView.m
│ ├── ZPLRowView.h
│ ├── ZPLRowView.m
│ ├── ZPLSuggestionCell.h
│ └── ZPLSuggestionCell.m
│ ├── ZPLAutocompletePluginController.h
│ └── ZPLAutocompletePluginController.m
├── LICENSE
├── README.md
├── fastlane
├── Fastfile
└── README.md
├── img
├── demo.gif
├── iconTransparent.png
└── logo.svg
├── plugin
├── img
│ ├── icon.png
│ ├── iconRunner.png
│ └── iconRunnerDark.png
├── manifest.json
└── src
│ └── index.js
└── pull_request_template.md
/.appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Emoji Autocomplete Sketch Plugin
5 | Type “:” followed by the first few letters to autocomplete emojis.
6 | en
7 | -
8 | Version 1.3
9 |
10 |
12 | You can now add emojis from Unicode 12.0, 13.0, and 14.0.
13 | Make plugin compatible with Apple M1.
14 |
15 | ]]>
16 |
17 |
18 |
19 | -
20 | Version 1.2
21 |
22 |
24 | More emojis! You can now add emojis from Unicode 10.0 and 11.0.
25 | Suggestion window now respects the visible screen boundaries on both axis.getting out of bounds on Y axes.
26 | Check emoji tags when finding suggestions.
27 |
28 | ]]>
29 |
30 |
31 |
32 | -
33 | Version 1.1
34 |
35 |
37 | Fixed text overrides emoji autocomplete not working on Sketch 52.
38 | Added dark mode icon for Runner.
39 | Fixed suggestion window getting out of bounds on X axis when editing text overrides.
40 |
41 | ]]>
42 |
43 |
44 |
45 | -
46 | Version 1.0
47 |
48 |
50 | Added dark mode support, along with Sketch 52.
51 |
52 | ]]>
53 |
54 |
55 |
56 | -
57 | Version 0.2
58 |
59 |
61 | You can now autocomplete emojis while editing overrides and layer names.
62 | Added icon for Runner.
63 |
64 | ]]>
65 |
66 |
67 |
68 | -
69 | Version 0.1
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | xcuserdata
3 | build
4 | fastlane/report.xml
5 | Autocomplete/Resources/Emojis.plist
6 |
--------------------------------------------------------------------------------
/Autocomplete.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3435B73920E6C0C100A04DBC /* Autocomplete.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B73720E6C0C100A04DBC /* Autocomplete.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 3435B74120E6C14D00A04DBC /* ZPLAutocompletePluginController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B73F20E6C14D00A04DBC /* ZPLAutocompletePluginController.h */; settings = {ATTRIBUTES = (Public, ); }; };
12 | 3435B74220E6C14D00A04DBC /* ZPLAutocompletePluginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B74020E6C14D00A04DBC /* ZPLAutocompletePluginController.m */; };
13 | 3435B74620E6C48E00A04DBC /* Emojis.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3435B74520E6C48E00A04DBC /* Emojis.plist */; };
14 | 3435B74A20E6C51F00A04DBC /* ZPLEmojiController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B74820E6C51F00A04DBC /* ZPLEmojiController.h */; };
15 | 3435B74B20E6C51F00A04DBC /* ZPLEmojiController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B74920E6C51F00A04DBC /* ZPLEmojiController.m */; };
16 | 3435B75320E6C57600A04DBC /* ZPLEmoji.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B75120E6C57600A04DBC /* ZPLEmoji.h */; };
17 | 3435B75420E6C57600A04DBC /* ZPLEmoji.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B75220E6C57600A04DBC /* ZPLEmoji.m */; };
18 | 3435B75820E6C64C00A04DBC /* ZPLSuggestionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B75620E6C64C00A04DBC /* ZPLSuggestionController.h */; };
19 | 3435B75920E6C64C00A04DBC /* ZPLSuggestionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B75720E6C64C00A04DBC /* ZPLSuggestionController.m */; };
20 | 3435B75C20E6C6B500A04DBC /* ZPLSuggestion.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B75A20E6C6B500A04DBC /* ZPLSuggestion.h */; };
21 | 3435B75D20E6C6B500A04DBC /* ZPLSuggestion.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B75B20E6C6B500A04DBC /* ZPLSuggestion.m */; };
22 | 3435B76020E6C76100A04DBC /* ZPLSuggestionCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B75E20E6C76100A04DBC /* ZPLSuggestionCell.h */; };
23 | 3435B76120E6C76100A04DBC /* ZPLSuggestionCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B75F20E6C76100A04DBC /* ZPLSuggestionCell.m */; };
24 | 3435B76520E6C7F800A04DBC /* ZPLFocusTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B76320E6C7F800A04DBC /* ZPLFocusTableView.h */; };
25 | 3435B76620E6C7F800A04DBC /* ZPLFocusTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B76420E6C7F800A04DBC /* ZPLFocusTableView.m */; };
26 | 3435B76920E6C83800A04DBC /* ZPLSuggestionWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = 3435B76720E6C83800A04DBC /* ZPLSuggestionWindowController.h */; };
27 | 3435B76A20E6C83800A04DBC /* ZPLSuggestionWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3435B76820E6C83800A04DBC /* ZPLSuggestionWindowController.m */; };
28 | 343DDD0920F51B450087E1CB /* NSView+Autocomplete.h in Headers */ = {isa = PBXBuildFile; fileRef = 343DDD0720F51B450087E1CB /* NSView+Autocomplete.h */; };
29 | 343DDD0A20F51B450087E1CB /* NSView+Autocomplete.m in Sources */ = {isa = PBXBuildFile; fileRef = 343DDD0820F51B450087E1CB /* NSView+Autocomplete.m */; };
30 | C0840FD220F37E1D00AEAE81 /* ZPLRowView.h in Headers */ = {isa = PBXBuildFile; fileRef = C0840FD020F37E1D00AEAE81 /* ZPLRowView.h */; };
31 | C0840FD320F37E1D00AEAE81 /* ZPLRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = C0840FD120F37E1D00AEAE81 /* ZPLRowView.m */; };
32 | C0840FD720F3B46400AEAE81 /* NSColor+Autocomplete.h in Headers */ = {isa = PBXBuildFile; fileRef = C0840FD520F3B46400AEAE81 /* NSColor+Autocomplete.h */; };
33 | C0840FD820F3B46400AEAE81 /* NSColor+Autocomplete.m in Sources */ = {isa = PBXBuildFile; fileRef = C0840FD620F3B46400AEAE81 /* NSColor+Autocomplete.m */; };
34 | C0C13FDB21699E2800E85491 /* ZPLTheme.h in Headers */ = {isa = PBXBuildFile; fileRef = C0C13FDA21699E2800E85491 /* ZPLTheme.h */; };
35 | /* End PBXBuildFile section */
36 |
37 | /* Begin PBXFileReference section */
38 | 3435B73420E6C0C100A04DBC /* Autocomplete.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Autocomplete.framework; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 3435B73720E6C0C100A04DBC /* Autocomplete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Autocomplete.h; sourceTree = ""; };
40 | 3435B73820E6C0C100A04DBC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | 3435B73F20E6C14D00A04DBC /* ZPLAutocompletePluginController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLAutocompletePluginController.h; sourceTree = ""; };
42 | 3435B74020E6C14D00A04DBC /* ZPLAutocompletePluginController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLAutocompletePluginController.m; sourceTree = ""; };
43 | 3435B74520E6C48E00A04DBC /* Emojis.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Emojis.plist; sourceTree = ""; };
44 | 3435B74820E6C51F00A04DBC /* ZPLEmojiController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLEmojiController.h; sourceTree = ""; };
45 | 3435B74920E6C51F00A04DBC /* ZPLEmojiController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLEmojiController.m; sourceTree = ""; };
46 | 3435B75120E6C57600A04DBC /* ZPLEmoji.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLEmoji.h; sourceTree = ""; };
47 | 3435B75220E6C57600A04DBC /* ZPLEmoji.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLEmoji.m; sourceTree = ""; };
48 | 3435B75620E6C64C00A04DBC /* ZPLSuggestionController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLSuggestionController.h; sourceTree = ""; };
49 | 3435B75720E6C64C00A04DBC /* ZPLSuggestionController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLSuggestionController.m; sourceTree = ""; };
50 | 3435B75A20E6C6B500A04DBC /* ZPLSuggestion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLSuggestion.h; sourceTree = ""; };
51 | 3435B75B20E6C6B500A04DBC /* ZPLSuggestion.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLSuggestion.m; sourceTree = ""; };
52 | 3435B75E20E6C76100A04DBC /* ZPLSuggestionCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLSuggestionCell.h; sourceTree = ""; };
53 | 3435B75F20E6C76100A04DBC /* ZPLSuggestionCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLSuggestionCell.m; sourceTree = ""; };
54 | 3435B76320E6C7F800A04DBC /* ZPLFocusTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLFocusTableView.h; sourceTree = ""; };
55 | 3435B76420E6C7F800A04DBC /* ZPLFocusTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLFocusTableView.m; sourceTree = ""; };
56 | 3435B76720E6C83800A04DBC /* ZPLSuggestionWindowController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLSuggestionWindowController.h; sourceTree = ""; };
57 | 3435B76820E6C83800A04DBC /* ZPLSuggestionWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLSuggestionWindowController.m; sourceTree = ""; };
58 | 343DDD0720F51B450087E1CB /* NSView+Autocomplete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSView+Autocomplete.h"; sourceTree = ""; };
59 | 343DDD0820F51B450087E1CB /* NSView+Autocomplete.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSView+Autocomplete.m"; sourceTree = ""; };
60 | C0840FD020F37E1D00AEAE81 /* ZPLRowView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLRowView.h; sourceTree = ""; };
61 | C0840FD120F37E1D00AEAE81 /* ZPLRowView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZPLRowView.m; sourceTree = ""; };
62 | C0840FD520F3B46400AEAE81 /* NSColor+Autocomplete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSColor+Autocomplete.h"; sourceTree = ""; };
63 | C0840FD620F3B46400AEAE81 /* NSColor+Autocomplete.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSColor+Autocomplete.m"; sourceTree = ""; };
64 | C0C13FDA21699E2800E85491 /* ZPLTheme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ZPLTheme.h; sourceTree = ""; };
65 | /* End PBXFileReference section */
66 |
67 | /* Begin PBXFrameworksBuildPhase section */
68 | 3435B73020E6C0C100A04DBC /* Frameworks */ = {
69 | isa = PBXFrameworksBuildPhase;
70 | buildActionMask = 2147483647;
71 | files = (
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | /* End PBXFrameworksBuildPhase section */
76 |
77 | /* Begin PBXGroup section */
78 | 3435B72A20E6C0C100A04DBC = {
79 | isa = PBXGroup;
80 | children = (
81 | 3435B73620E6C0C100A04DBC /* Autocomplete */,
82 | 3435B73520E6C0C100A04DBC /* Products */,
83 | );
84 | sourceTree = "";
85 | };
86 | 3435B73520E6C0C100A04DBC /* Products */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 3435B73420E6C0C100A04DBC /* Autocomplete.framework */,
90 | );
91 | name = Products;
92 | sourceTree = "";
93 | };
94 | 3435B73620E6C0C100A04DBC /* Autocomplete */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 3435B74420E6C29C00A04DBC /* Sources */,
98 | 3435B74720E6C4A400A04DBC /* Resources */,
99 | 3435B73720E6C0C100A04DBC /* Autocomplete.h */,
100 | 3435B73820E6C0C100A04DBC /* Info.plist */,
101 | );
102 | path = Autocomplete;
103 | sourceTree = "";
104 | };
105 | 3435B74420E6C29C00A04DBC /* Sources */ = {
106 | isa = PBXGroup;
107 | children = (
108 | 3435B73F20E6C14D00A04DBC /* ZPLAutocompletePluginController.h */,
109 | 3435B74020E6C14D00A04DBC /* ZPLAutocompletePluginController.m */,
110 | 3435B75520E6C57B00A04DBC /* Models */,
111 | 3435B76220E6C76800A04DBC /* Views */,
112 | 3435B74C20E6C52200A04DBC /* Controllers */,
113 | C0840FD420F3B43C00AEAE81 /* Categories */,
114 | );
115 | path = Sources;
116 | sourceTree = "";
117 | };
118 | 3435B74720E6C4A400A04DBC /* Resources */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 3435B74520E6C48E00A04DBC /* Emojis.plist */,
122 | );
123 | path = Resources;
124 | sourceTree = "";
125 | };
126 | 3435B74C20E6C52200A04DBC /* Controllers */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 3435B74820E6C51F00A04DBC /* ZPLEmojiController.h */,
130 | 3435B74920E6C51F00A04DBC /* ZPLEmojiController.m */,
131 | 3435B75620E6C64C00A04DBC /* ZPLSuggestionController.h */,
132 | 3435B75720E6C64C00A04DBC /* ZPLSuggestionController.m */,
133 | 3435B76720E6C83800A04DBC /* ZPLSuggestionWindowController.h */,
134 | 3435B76820E6C83800A04DBC /* ZPLSuggestionWindowController.m */,
135 | );
136 | path = Controllers;
137 | sourceTree = "";
138 | };
139 | 3435B75520E6C57B00A04DBC /* Models */ = {
140 | isa = PBXGroup;
141 | children = (
142 | 3435B75120E6C57600A04DBC /* ZPLEmoji.h */,
143 | 3435B75220E6C57600A04DBC /* ZPLEmoji.m */,
144 | 3435B75A20E6C6B500A04DBC /* ZPLSuggestion.h */,
145 | 3435B75B20E6C6B500A04DBC /* ZPLSuggestion.m */,
146 | C0C13FD921699DF000E85491 /* Sketch */,
147 | );
148 | path = Models;
149 | sourceTree = "";
150 | };
151 | 3435B76220E6C76800A04DBC /* Views */ = {
152 | isa = PBXGroup;
153 | children = (
154 | 3435B76320E6C7F800A04DBC /* ZPLFocusTableView.h */,
155 | 3435B76420E6C7F800A04DBC /* ZPLFocusTableView.m */,
156 | 3435B75E20E6C76100A04DBC /* ZPLSuggestionCell.h */,
157 | 3435B75F20E6C76100A04DBC /* ZPLSuggestionCell.m */,
158 | C0840FD020F37E1D00AEAE81 /* ZPLRowView.h */,
159 | C0840FD120F37E1D00AEAE81 /* ZPLRowView.m */,
160 | );
161 | path = Views;
162 | sourceTree = "";
163 | };
164 | C0840FD420F3B43C00AEAE81 /* Categories */ = {
165 | isa = PBXGroup;
166 | children = (
167 | C0840FD520F3B46400AEAE81 /* NSColor+Autocomplete.h */,
168 | C0840FD620F3B46400AEAE81 /* NSColor+Autocomplete.m */,
169 | 343DDD0720F51B450087E1CB /* NSView+Autocomplete.h */,
170 | 343DDD0820F51B450087E1CB /* NSView+Autocomplete.m */,
171 | );
172 | path = Categories;
173 | sourceTree = "";
174 | };
175 | C0C13FD921699DF000E85491 /* Sketch */ = {
176 | isa = PBXGroup;
177 | children = (
178 | C0C13FDA21699E2800E85491 /* ZPLTheme.h */,
179 | );
180 | path = Sketch;
181 | sourceTree = "";
182 | };
183 | /* End PBXGroup section */
184 |
185 | /* Begin PBXHeadersBuildPhase section */
186 | 3435B73120E6C0C100A04DBC /* Headers */ = {
187 | isa = PBXHeadersBuildPhase;
188 | buildActionMask = 2147483647;
189 | files = (
190 | 3435B76920E6C83800A04DBC /* ZPLSuggestionWindowController.h in Headers */,
191 | 3435B74120E6C14D00A04DBC /* ZPLAutocompletePluginController.h in Headers */,
192 | 3435B75820E6C64C00A04DBC /* ZPLSuggestionController.h in Headers */,
193 | 3435B76520E6C7F800A04DBC /* ZPLFocusTableView.h in Headers */,
194 | 3435B73920E6C0C100A04DBC /* Autocomplete.h in Headers */,
195 | C0840FD220F37E1D00AEAE81 /* ZPLRowView.h in Headers */,
196 | C0C13FDB21699E2800E85491 /* ZPLTheme.h in Headers */,
197 | 3435B75C20E6C6B500A04DBC /* ZPLSuggestion.h in Headers */,
198 | 3435B76020E6C76100A04DBC /* ZPLSuggestionCell.h in Headers */,
199 | 343DDD0920F51B450087E1CB /* NSView+Autocomplete.h in Headers */,
200 | 3435B75320E6C57600A04DBC /* ZPLEmoji.h in Headers */,
201 | C0840FD720F3B46400AEAE81 /* NSColor+Autocomplete.h in Headers */,
202 | 3435B74A20E6C51F00A04DBC /* ZPLEmojiController.h in Headers */,
203 | );
204 | runOnlyForDeploymentPostprocessing = 0;
205 | };
206 | /* End PBXHeadersBuildPhase section */
207 |
208 | /* Begin PBXNativeTarget section */
209 | 3435B73320E6C0C100A04DBC /* Autocomplete */ = {
210 | isa = PBXNativeTarget;
211 | buildConfigurationList = 3435B73C20E6C0C100A04DBC /* Build configuration list for PBXNativeTarget "Autocomplete" */;
212 | buildPhases = (
213 | 3435B72F20E6C0C100A04DBC /* Sources */,
214 | 3435B73020E6C0C100A04DBC /* Frameworks */,
215 | 3435B73120E6C0C100A04DBC /* Headers */,
216 | 3435B73220E6C0C100A04DBC /* Resources */,
217 | );
218 | buildRules = (
219 | );
220 | dependencies = (
221 | );
222 | name = Autocomplete;
223 | productName = Autocomplete;
224 | productReference = 3435B73420E6C0C100A04DBC /* Autocomplete.framework */;
225 | productType = "com.apple.product-type.framework";
226 | };
227 | /* End PBXNativeTarget section */
228 |
229 | /* Begin PBXProject section */
230 | 3435B72B20E6C0C100A04DBC /* Project object */ = {
231 | isa = PBXProject;
232 | attributes = {
233 | LastUpgradeCheck = 1000;
234 | ORGANIZATIONNAME = "Zeplin, Inc.";
235 | TargetAttributes = {
236 | 3435B73320E6C0C100A04DBC = {
237 | CreatedOnToolsVersion = 9.4;
238 | };
239 | };
240 | };
241 | buildConfigurationList = 3435B72E20E6C0C100A04DBC /* Build configuration list for PBXProject "Autocomplete" */;
242 | compatibilityVersion = "Xcode 9.3";
243 | developmentRegion = en;
244 | hasScannedForEncodings = 0;
245 | knownRegions = (
246 | en,
247 | );
248 | mainGroup = 3435B72A20E6C0C100A04DBC;
249 | productRefGroup = 3435B73520E6C0C100A04DBC /* Products */;
250 | projectDirPath = "";
251 | projectRoot = "";
252 | targets = (
253 | 3435B73320E6C0C100A04DBC /* Autocomplete */,
254 | );
255 | };
256 | /* End PBXProject section */
257 |
258 | /* Begin PBXResourcesBuildPhase section */
259 | 3435B73220E6C0C100A04DBC /* Resources */ = {
260 | isa = PBXResourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | 3435B74620E6C48E00A04DBC /* Emojis.plist in Resources */,
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | };
267 | /* End PBXResourcesBuildPhase section */
268 |
269 | /* Begin PBXSourcesBuildPhase section */
270 | 3435B72F20E6C0C100A04DBC /* Sources */ = {
271 | isa = PBXSourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | 3435B75420E6C57600A04DBC /* ZPLEmoji.m in Sources */,
275 | 3435B74220E6C14D00A04DBC /* ZPLAutocompletePluginController.m in Sources */,
276 | 3435B76120E6C76100A04DBC /* ZPLSuggestionCell.m in Sources */,
277 | 3435B76620E6C7F800A04DBC /* ZPLFocusTableView.m in Sources */,
278 | C0840FD320F37E1D00AEAE81 /* ZPLRowView.m in Sources */,
279 | 3435B76A20E6C83800A04DBC /* ZPLSuggestionWindowController.m in Sources */,
280 | 3435B75920E6C64C00A04DBC /* ZPLSuggestionController.m in Sources */,
281 | 3435B75D20E6C6B500A04DBC /* ZPLSuggestion.m in Sources */,
282 | C0840FD820F3B46400AEAE81 /* NSColor+Autocomplete.m in Sources */,
283 | 343DDD0A20F51B450087E1CB /* NSView+Autocomplete.m in Sources */,
284 | 3435B74B20E6C51F00A04DBC /* ZPLEmojiController.m in Sources */,
285 | );
286 | runOnlyForDeploymentPostprocessing = 0;
287 | };
288 | /* End PBXSourcesBuildPhase section */
289 |
290 | /* Begin XCBuildConfiguration section */
291 | 3435B73A20E6C0C100A04DBC /* Debug */ = {
292 | isa = XCBuildConfiguration;
293 | buildSettings = {
294 | ALWAYS_SEARCH_USER_PATHS = NO;
295 | CLANG_ANALYZER_NONNULL = YES;
296 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
298 | CLANG_CXX_LIBRARY = "libc++";
299 | CLANG_ENABLE_MODULES = YES;
300 | CLANG_ENABLE_OBJC_ARC = YES;
301 | CLANG_ENABLE_OBJC_WEAK = YES;
302 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
303 | CLANG_WARN_BOOL_CONVERSION = YES;
304 | CLANG_WARN_COMMA = YES;
305 | CLANG_WARN_CONSTANT_CONVERSION = YES;
306 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
307 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
308 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
309 | CLANG_WARN_EMPTY_BODY = YES;
310 | CLANG_WARN_ENUM_CONVERSION = YES;
311 | CLANG_WARN_INFINITE_RECURSION = YES;
312 | CLANG_WARN_INT_CONVERSION = YES;
313 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
314 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
315 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
316 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
317 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
318 | CLANG_WARN_STRICT_PROTOTYPES = YES;
319 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
320 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
321 | CLANG_WARN_UNREACHABLE_CODE = YES;
322 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
323 | CODE_SIGN_IDENTITY = "Mac Developer";
324 | COPY_PHASE_STRIP = NO;
325 | CURRENT_PROJECT_VERSION = 1;
326 | DEBUG_INFORMATION_FORMAT = dwarf;
327 | DEVELOPMENT_TEAM = 8U3Y4X5WDQ;
328 | ENABLE_STRICT_OBJC_MSGSEND = YES;
329 | ENABLE_TESTABILITY = YES;
330 | GCC_C_LANGUAGE_STANDARD = gnu11;
331 | GCC_DYNAMIC_NO_PIC = NO;
332 | GCC_NO_COMMON_BLOCKS = YES;
333 | GCC_OPTIMIZATION_LEVEL = 0;
334 | GCC_PREPROCESSOR_DEFINITIONS = (
335 | "DEBUG=1",
336 | "$(inherited)",
337 | );
338 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
339 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
340 | GCC_WARN_UNDECLARED_SELECTOR = YES;
341 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
342 | GCC_WARN_UNUSED_FUNCTION = YES;
343 | GCC_WARN_UNUSED_VARIABLE = YES;
344 | MACOSX_DEPLOYMENT_TARGET = 10.11;
345 | MTL_ENABLE_DEBUG_INFO = YES;
346 | ONLY_ACTIVE_ARCH = YES;
347 | SDKROOT = macosx;
348 | VERSIONING_SYSTEM = "apple-generic";
349 | VERSION_INFO_PREFIX = "";
350 | };
351 | name = Debug;
352 | };
353 | 3435B73B20E6C0C100A04DBC /* Release */ = {
354 | isa = XCBuildConfiguration;
355 | buildSettings = {
356 | ALWAYS_SEARCH_USER_PATHS = NO;
357 | CLANG_ANALYZER_NONNULL = YES;
358 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
359 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
360 | CLANG_CXX_LIBRARY = "libc++";
361 | CLANG_ENABLE_MODULES = YES;
362 | CLANG_ENABLE_OBJC_ARC = YES;
363 | CLANG_ENABLE_OBJC_WEAK = YES;
364 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
365 | CLANG_WARN_BOOL_CONVERSION = YES;
366 | CLANG_WARN_COMMA = YES;
367 | CLANG_WARN_CONSTANT_CONVERSION = YES;
368 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
369 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
370 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
371 | CLANG_WARN_EMPTY_BODY = YES;
372 | CLANG_WARN_ENUM_CONVERSION = YES;
373 | CLANG_WARN_INFINITE_RECURSION = YES;
374 | CLANG_WARN_INT_CONVERSION = YES;
375 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
376 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
377 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
378 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
379 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
380 | CLANG_WARN_STRICT_PROTOTYPES = YES;
381 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
382 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
383 | CLANG_WARN_UNREACHABLE_CODE = YES;
384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
385 | CODE_SIGN_IDENTITY = "Mac Developer";
386 | COPY_PHASE_STRIP = NO;
387 | CURRENT_PROJECT_VERSION = 1;
388 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
389 | DEVELOPMENT_TEAM = 8U3Y4X5WDQ;
390 | ENABLE_NS_ASSERTIONS = NO;
391 | ENABLE_STRICT_OBJC_MSGSEND = YES;
392 | GCC_C_LANGUAGE_STANDARD = gnu11;
393 | GCC_NO_COMMON_BLOCKS = YES;
394 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
395 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
396 | GCC_WARN_UNDECLARED_SELECTOR = YES;
397 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
398 | GCC_WARN_UNUSED_FUNCTION = YES;
399 | GCC_WARN_UNUSED_VARIABLE = YES;
400 | MACOSX_DEPLOYMENT_TARGET = 10.11;
401 | MTL_ENABLE_DEBUG_INFO = NO;
402 | SDKROOT = macosx;
403 | VERSIONING_SYSTEM = "apple-generic";
404 | VERSION_INFO_PREFIX = "";
405 | };
406 | name = Release;
407 | };
408 | 3435B73D20E6C0C100A04DBC /* Debug */ = {
409 | isa = XCBuildConfiguration;
410 | buildSettings = {
411 | CODE_SIGN_IDENTITY = "";
412 | COMBINE_HIDPI_IMAGES = YES;
413 | DEFINES_MODULE = YES;
414 | DYLIB_COMPATIBILITY_VERSION = 1;
415 | DYLIB_CURRENT_VERSION = 1;
416 | DYLIB_INSTALL_NAME_BASE = "@rpath";
417 | FRAMEWORK_VERSION = A;
418 | INFOPLIST_FILE = Autocomplete/Info.plist;
419 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
420 | LD_RUNPATH_SEARCH_PATHS = (
421 | "$(inherited)",
422 | "@executable_path/../Frameworks",
423 | "@loader_path/Frameworks",
424 | );
425 | PRODUCT_BUNDLE_IDENTIFIER = io.zeplin.Autocomplete;
426 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
427 | SKIP_INSTALL = YES;
428 | };
429 | name = Debug;
430 | };
431 | 3435B73E20E6C0C100A04DBC /* Release */ = {
432 | isa = XCBuildConfiguration;
433 | buildSettings = {
434 | CODE_SIGN_IDENTITY = "";
435 | COMBINE_HIDPI_IMAGES = YES;
436 | DEFINES_MODULE = YES;
437 | DYLIB_COMPATIBILITY_VERSION = 1;
438 | DYLIB_CURRENT_VERSION = 1;
439 | DYLIB_INSTALL_NAME_BASE = "@rpath";
440 | FRAMEWORK_VERSION = A;
441 | INFOPLIST_FILE = Autocomplete/Info.plist;
442 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
443 | LD_RUNPATH_SEARCH_PATHS = (
444 | "$(inherited)",
445 | "@executable_path/../Frameworks",
446 | "@loader_path/Frameworks",
447 | );
448 | PRODUCT_BUNDLE_IDENTIFIER = io.zeplin.Autocomplete;
449 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
450 | SKIP_INSTALL = YES;
451 | };
452 | name = Release;
453 | };
454 | /* End XCBuildConfiguration section */
455 |
456 | /* Begin XCConfigurationList section */
457 | 3435B72E20E6C0C100A04DBC /* Build configuration list for PBXProject "Autocomplete" */ = {
458 | isa = XCConfigurationList;
459 | buildConfigurations = (
460 | 3435B73A20E6C0C100A04DBC /* Debug */,
461 | 3435B73B20E6C0C100A04DBC /* Release */,
462 | );
463 | defaultConfigurationIsVisible = 0;
464 | defaultConfigurationName = Release;
465 | };
466 | 3435B73C20E6C0C100A04DBC /* Build configuration list for PBXNativeTarget "Autocomplete" */ = {
467 | isa = XCConfigurationList;
468 | buildConfigurations = (
469 | 3435B73D20E6C0C100A04DBC /* Debug */,
470 | 3435B73E20E6C0C100A04DBC /* Release */,
471 | );
472 | defaultConfigurationIsVisible = 0;
473 | defaultConfigurationName = Release;
474 | };
475 | /* End XCConfigurationList section */
476 | };
477 | rootObject = 3435B72B20E6C0C100A04DBC /* Project object */;
478 | }
479 |
--------------------------------------------------------------------------------
/Autocomplete.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Autocomplete.xcodeproj/project.xcworkspace/xcshareddata/IDETemplateMacros.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | COPYRIGHT
6 | Copyright © ___YEAR___ ___ORGANIZATIONNAME___
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Autocomplete.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Autocomplete.xcodeproj/xcshareddata/xcschemes/Autocomplete.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
48 |
51 |
52 |
58 |
59 |
60 |
61 |
62 |
63 |
67 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/Autocomplete/Autocomplete.h:
--------------------------------------------------------------------------------
1 | //
2 | // Autocomplete.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE
25 | //
26 |
27 | #import
28 |
29 | FOUNDATION_EXPORT double AutocompleteVersionNumber;
30 | FOUNDATION_EXPORT const unsigned char AutocompleteVersionString[];
31 |
32 | #import
33 |
--------------------------------------------------------------------------------
/Autocomplete/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.3
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSHumanReadableCopyright
22 | Copyright © 2022 Zeplin, Inc.
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Categories/NSColor+Autocomplete.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSColor+Autocomplete.h
3 | // Autocomplete
4 | //
5 | // Created by K. Berk Cebi on 7/9/18.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @interface NSColor (Autocomplete)
30 |
31 | + (NSColor *)zpl_backgroundColor;
32 | + (NSColor *)zpl_selectionColor;
33 | + (NSColor *)zpl_textColor;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Categories/NSColor+Autocomplete.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSColor+Autocomplete.m
3 | // Autocomplete
4 | //
5 | // Created by K. Berk Cebi on 7/9/18.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "NSColor+Autocomplete.h"
28 |
29 | #import "ZPLTheme.h"
30 |
31 | @implementation NSColor (Autocomplete)
32 |
33 | + (NSColor *)zpl_backgroundColor {
34 | NSObject *theme = [self zpl_currentTheme];
35 | if (!theme) {
36 | return nil;
37 | }
38 |
39 | return [theme layerListBackgroundColor];
40 | }
41 |
42 | + (NSColor *)zpl_selectionColor {
43 | NSObject *theme = [self zpl_currentTheme];
44 | if (!theme) {
45 | return [NSColor colorWithDeviceRed:105.0f / 255.0f green:155.0f / 255.0f blue:228.0f / 255.0f alpha:1.0f];
46 | }
47 |
48 | return [theme inspectorAccentColor];
49 | }
50 |
51 | + (NSColor *)zpl_textColor {
52 | NSObject *theme = [self zpl_currentTheme];
53 | if (!theme) {
54 | return nil;
55 | }
56 |
57 | return [theme inspectorLabelTextColor];
58 | }
59 |
60 | #pragma mark - Private
61 |
62 | + (NSObject *)zpl_currentTheme {
63 | Class themeClass = NSClassFromString(ZPLThemeClassName);
64 | if (!themeClass) {
65 | return nil;
66 | }
67 |
68 | return [themeClass sharedTheme];
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Categories/NSView+Autocomplete.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSView+Autocomplete.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 10.07.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @interface NSView (Autocomplete)
30 |
31 | - (BOOL)zpl_nextRespondersContainClassFromNames:(NSArray *)classNames;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Categories/NSView+Autocomplete.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSView+Autocomplete.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 10.07.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "NSView+Autocomplete.h"
28 |
29 | @implementation NSView (Autocomplete)
30 |
31 | - (BOOL)zpl_nextRespondersContainClassFromNames:(NSArray *)classNames {
32 | for (NSResponder *nextResponder = self.nextResponder; nextResponder; nextResponder = nextResponder.nextResponder) {
33 | for (NSString *className in classNames) {
34 | if ([nextResponder isKindOfClass:NSClassFromString(className)]) {
35 | return YES;
36 | }
37 | }
38 | }
39 |
40 | return NO;
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLEmojiController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLEmojiController.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | #import "ZPLEmoji.h"
30 |
31 | @interface ZPLEmojiController : NSObject
32 |
33 | @property (strong, nonatomic) NSArray *emojis;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLEmojiController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLEmojiController.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLEmojiController.h"
28 |
29 | #import "ZPLAutocompletePluginController.h"
30 |
31 | @implementation ZPLEmojiController
32 |
33 | #pragma mark - Initializers
34 |
35 | - (instancetype)init {
36 | self = [super init];
37 | if (!self) {
38 | return nil;
39 | }
40 |
41 | NSBundle *bundle = [NSBundle bundleForClass:[ZPLAutocompletePluginController class]];
42 | NSString *emojiListPath = [bundle pathForResource:@"Emojis" ofType:@"plist"];
43 | NSArray *emojiDictionaries = (NSArray *)[NSArray arrayWithContentsOfFile:emojiListPath];
44 |
45 | NSMutableArray *emojis = [NSMutableArray array];
46 | for (NSDictionary *emojiDictionary in emojiDictionaries) {
47 | ZPLEmoji *emoji = [[ZPLEmoji alloc] initWithDictionary:emojiDictionary];
48 |
49 | if (!emoji) {
50 | continue;
51 | }
52 |
53 | [emojis addObject:emoji];
54 | }
55 |
56 | self.emojis = emojis;
57 |
58 | return self;
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLSuggestionController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionController.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @interface ZPLSuggestionController : NSObject
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLSuggestionController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionController.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLSuggestionController.h"
28 |
29 | #import "ZPLEmoji.h"
30 | #import "ZPLSuggestion.h"
31 | #import "ZPLEmojiController.h"
32 | #import "ZPLSuggestionWindowController.h"
33 |
34 | #import "NSView+Autocomplete.h"
35 |
36 | static NSString * const ZPLSuggestionDelimeter = @":";
37 | static NSString * const MSTextLayerTextViewClassName = @"MSTextLayerTextView";
38 | static NSString * const MSOverrideTextFieldClassName = @"MSOverrideTextField";
39 | static NSString * const BCPageListViewControllerClassName = @"BCPageListViewController";
40 | static NSString * const BCLayerListViewControllerClassName = @"BCLayerListViewController";
41 | static NSString * const MSTextOverrideViewControllerClassName = @"MSTextOverrideViewController";
42 | static NSString * const MSTextOverrideInspectorItemClassName = @"MSTextOverrideInspectorItem";
43 |
44 | @interface ZPLSuggestionController ()
45 |
46 | @property (strong, nonatomic) ZPLEmojiController *emojiController;
47 | @property (strong, nonatomic) ZPLSuggestionWindowController *windowController;
48 |
49 | @property (strong, nonatomic) NSCharacterSet *invertedCharacterSet;
50 | @property (strong, nonatomic) NSArray *responderClassNames;
51 |
52 | @property (strong, nonatomic) NSTextView *positioningTextView;
53 |
54 | @end
55 |
56 | @implementation ZPLSuggestionController
57 |
58 | #pragma mark - Initializers
59 |
60 | - (void)dealloc {
61 | [[NSNotificationCenter defaultCenter] removeObserver:self];
62 | }
63 |
64 | - (instancetype)init {
65 | self = [super init];
66 | if (!self) {
67 | return nil;
68 | }
69 |
70 | _emojiController = [[ZPLEmojiController alloc] init];
71 | _invertedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyz0123456789_"] invertedSet];
72 | _responderClassNames = @[BCPageListViewControllerClassName, BCLayerListViewControllerClassName, MSTextOverrideViewControllerClassName, MSTextOverrideInspectorItemClassName];
73 |
74 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewDidChangeSelection:) name:NSTextViewDidChangeSelectionNotification object:nil];
75 |
76 | return self;
77 | }
78 |
79 | #pragma mark - Private
80 |
81 | - (void)dismissWindowController {
82 | [self.windowController dismiss];
83 | self.windowController = nil;
84 | }
85 |
86 | - (void)reloadSuggestionsForTextView:(NSTextView *)textView {
87 | NSArray *suggestions = [self suggestionsForTextView:textView];
88 |
89 | if (suggestions.count == 0) {
90 | [self dismissWindowController];
91 |
92 | return;
93 | }
94 |
95 | if (!self.windowController) {
96 | self.windowController = [[ZPLSuggestionWindowController alloc] init];
97 | self.windowController.delegate = self;
98 | }
99 |
100 | self.positioningTextView = textView;
101 | [self.windowController presentWithSuggestions:suggestions positioningTextView:textView];
102 | }
103 |
104 | - (NSArray *)suggestionsForTextView:(NSTextView *)textView {
105 | NSRange keywordRange = [self keywordRangeForTextView:textView];
106 |
107 | if (keywordRange.location == NSNotFound) {
108 | return @[];
109 | }
110 |
111 | NSString *text = [textView.string lowercaseString];
112 | NSString *keyword = [text substringWithRange:keywordRange];
113 | NSMutableArray *suggestions = [NSMutableArray array];
114 |
115 | for (ZPLEmoji *emoji in self.emojiController.emojis) {
116 | BOOL suggestionAdded = NO;
117 |
118 | for (NSString *alias in emoji.aliases) {
119 | if ([alias hasPrefix:keyword]) {
120 | ZPLSuggestion *suggestion = [[ZPLSuggestion alloc] init];
121 | suggestion.emoji = emoji;
122 | suggestion.alias = alias;
123 |
124 | [suggestions addObject:suggestion];
125 | suggestionAdded = YES;
126 |
127 | break;
128 | }
129 |
130 | NSArray *aliasComponents = [alias componentsSeparatedByString:ZPLEmojiAliasSeparator];
131 |
132 | if (aliasComponents.count <= 1) {
133 | continue;
134 | }
135 |
136 | for (NSString *aliasComponent in aliasComponents) {
137 | if ([aliasComponent hasPrefix:keyword]) {
138 | ZPLSuggestion *suggestion = [[ZPLSuggestion alloc] init];
139 | suggestion.emoji = emoji;
140 | suggestion.alias = alias;
141 |
142 | [suggestions addObject:suggestion];
143 | suggestionAdded = YES;
144 |
145 | break;
146 | }
147 | }
148 | }
149 |
150 | if (suggestionAdded) {
151 | continue;
152 | }
153 |
154 | for (NSString *tag in emoji.tags) {
155 | if ([tag hasPrefix:keyword]) {
156 | ZPLSuggestion *suggestion = [[ZPLSuggestion alloc] init];
157 | suggestion.emoji = emoji;
158 | suggestion.alias = [[emoji aliases] firstObject];
159 |
160 | [suggestions addObject:suggestion];
161 | suggestionAdded = YES;
162 |
163 | break;
164 | }
165 | }
166 | }
167 |
168 | return suggestions;
169 | }
170 |
171 | - (NSRange)keywordRangeForTextView:(NSTextView *)textView {
172 | if (textView.selectedRanges.firstObject == nil) {
173 | return NSMakeRange(NSNotFound, 0);
174 | }
175 |
176 | NSRange range = textView.selectedRanges.firstObject.rangeValue;
177 |
178 | if (range.length != 0) {
179 | return NSMakeRange(NSNotFound, 0);
180 | }
181 |
182 | NSString *text = [textView.string lowercaseString];
183 | NSString *leftText = [text substringToIndex:range.location];
184 | NSString *rightText = [text substringFromIndex:range.location];
185 |
186 | NSRange leftInvalidCharacterRange = [leftText rangeOfCharacterFromSet:self.invertedCharacterSet options:NSBackwardsSearch];
187 | if (leftInvalidCharacterRange.location == NSNotFound
188 | || ![[leftText substringWithRange:leftInvalidCharacterRange] isEqualToString:ZPLSuggestionDelimeter]) {
189 | return NSMakeRange(NSNotFound, 0);
190 | }
191 |
192 | NSUInteger rightInvalidCharacterIndex = [rightText rangeOfCharacterFromSet:self.invertedCharacterSet].location;
193 | if (rightInvalidCharacterIndex == NSNotFound) {
194 | rightInvalidCharacterIndex = rightText.length;
195 | }
196 |
197 | NSUInteger keywordLocation = leftInvalidCharacterRange.location + ZPLSuggestionDelimeter.length;
198 | NSUInteger keywordLength = range.location + rightInvalidCharacterIndex - keywordLocation;
199 |
200 | return NSMakeRange(keywordLocation, keywordLength);
201 | }
202 |
203 | #pragma mark - Notifications
204 |
205 | - (void)textViewDidChangeSelection:(NSNotification *)notification {
206 | NSTextView *textView = (NSTextView *)notification.object;
207 |
208 | if (![textView isKindOfClass:NSClassFromString(MSTextLayerTextViewClassName)] &&
209 | ![textView.delegate isKindOfClass:NSClassFromString(MSOverrideTextFieldClassName)] &&
210 | ![textView zpl_nextRespondersContainClassFromNames:self.responderClassNames]) {
211 | [self dismissWindowController];
212 |
213 | return;
214 | }
215 |
216 | [self reloadSuggestionsForTextView:textView];
217 | }
218 |
219 | #pragma mark - ZPLSuggestionWindowControllerDelegate
220 |
221 | - (void)suggestionWindowController:(ZPLSuggestionWindowController *)suggestionWindowController didSelectSuggestion:(ZPLSuggestion *)suggestion {
222 | if (!self.positioningTextView) {
223 | return;
224 | }
225 |
226 | NSRange keywordRange = [self keywordRangeForTextView:self.positioningTextView];
227 |
228 | if (keywordRange.location == NSNotFound) {
229 | return;
230 | }
231 |
232 | keywordRange = NSMakeRange(keywordRange.location - ZPLSuggestionDelimeter.length, keywordRange.length + ZPLSuggestionDelimeter.length);
233 | NSUInteger keywordMaxRange = NSMaxRange(keywordRange);
234 |
235 | BOOL hasWhitespaceSuffix = NO;
236 | if (keywordMaxRange < self.positioningTextView.string.length - 1) {
237 | NSString *nextCharacterString = [self.positioningTextView.string substringWithRange:NSMakeRange(keywordMaxRange, 1)];
238 |
239 | if ([nextCharacterString rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]].location != NSNotFound) {
240 | hasWhitespaceSuffix = YES;
241 | }
242 | }
243 |
244 | NSString *replacement;
245 | if (hasWhitespaceSuffix) {
246 | replacement = [suggestion.emoji.value copy];
247 | } else {
248 | replacement = [NSString stringWithFormat:@"%@ ", suggestion.emoji.value];
249 | }
250 |
251 | [[self.positioningTextView textStorage] replaceCharactersInRange:keywordRange withString:replacement];
252 | }
253 |
254 | - (NSRange)suggestionWindowController:(ZPLSuggestionWindowController *)suggestionWindowController keywordRangeForTextView:(NSTextView *)textView {
255 | return [self keywordRangeForTextView:textView];
256 | }
257 |
258 | @end
259 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLSuggestionWindowController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionWindowController.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @class ZPLSuggestion;
30 |
31 | @protocol ZPLSuggestionWindowControllerDelegate;
32 |
33 | @interface ZPLSuggestionWindowController : NSWindowController
34 |
35 | @property (weak, nonatomic) id delegate;
36 |
37 | - (void)presentWithSuggestions:(NSArray *)suggestions positioningTextView:(NSTextView *)positioningTextView;
38 | - (void)dismiss;
39 |
40 | @end
41 |
42 | @protocol ZPLSuggestionWindowControllerDelegate
43 |
44 | - (void)suggestionWindowController:(ZPLSuggestionWindowController *)suggestionWindowController didSelectSuggestion:(ZPLSuggestion *)suggestion;
45 | - (NSRange)suggestionWindowController:(ZPLSuggestionWindowController *)suggestionWindowController keywordRangeForTextView:(NSTextView *)textView;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Controllers/ZPLSuggestionWindowController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionWindowController.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLSuggestionController.h"
28 |
29 | #import "ZPLSuggestionWindowController.h"
30 |
31 | #import "ZPLSuggestion.h"
32 | #import "ZPLFocusTableView.h"
33 | #import "ZPLSuggestionCell.h"
34 | #import "ZPLRowView.h"
35 | #import "NSColor+Autocomplete.h"
36 |
37 | static const CGFloat ZPLSuggestionWindowControllerContentViewCornerRadius = 3.0f;
38 | static const CGFloat ZPLSuggestionWindowControllerMargin = 8.0f;
39 |
40 | static const NSUInteger ZPLEventKeyCodeReturn = 36;
41 | static const NSUInteger ZPLEventKeyCodeTab = 48;
42 | static const NSUInteger ZPLEventKeyCodeEscape = 53;
43 | static const NSUInteger ZPLEventKeyCodeBottomArrow = 125;
44 | static const NSUInteger ZPLEventKeyCodeTopArrow = 126;
45 |
46 | static const NSSize ZPLSuggestionWindowControllerMaximumWindowSize = {.width = 190.0f, .height = 208.0f};
47 |
48 | @interface ZPLSuggestionWindowController ()
49 |
50 | @property (copy, nonatomic) NSArray *suggestions;
51 |
52 | @property (strong, nonatomic) ZPLFocusTableView *tableView;
53 |
54 | @property (strong, nonatomic) id mouseDownMonitor;
55 | @property (strong, nonatomic) id keyDownMonitor;
56 |
57 | @end
58 |
59 | @implementation ZPLSuggestionWindowController
60 |
61 | #pragma mark - Initializers
62 |
63 | - (void)dealloc {
64 | _tableView.delegate = nil;
65 | _tableView.dataSource = nil;
66 |
67 | if (_keyDownMonitor != nil) {
68 | [NSEvent removeMonitor:_keyDownMonitor];
69 | }
70 |
71 | if (_mouseDownMonitor != nil) {
72 | [NSEvent removeMonitor:_mouseDownMonitor];
73 | }
74 |
75 | [[NSNotificationCenter defaultCenter] removeObserver:self];
76 | }
77 |
78 | - (instancetype)init {
79 | self = [super initWithWindow:nil];
80 | if (!self) {
81 | return nil;
82 | }
83 |
84 | NSView *contentView = [[NSView alloc] init];
85 | contentView.wantsLayer = YES;
86 | contentView.layer.cornerRadius = ZPLSuggestionWindowControllerContentViewCornerRadius;
87 |
88 | _tableView = [[ZPLFocusTableView alloc] init];
89 | _tableView.headerView = nil;
90 | _tableView.intercellSpacing = NSZeroSize;
91 | _tableView.delegate = self;
92 | _tableView.dataSource = self;
93 | _tableView.allowsEmptySelection = NO;
94 |
95 | NSColor *tableViewBackgroundColor = [NSColor zpl_backgroundColor];
96 | if (tableViewBackgroundColor) {
97 | _tableView.backgroundColor = tableViewBackgroundColor;
98 | }
99 |
100 | NSScrollView *scrollView = [[NSScrollView alloc] init];
101 | scrollView.documentView = _tableView;
102 |
103 | [contentView addSubview:scrollView];
104 |
105 | contentView.translatesAutoresizingMaskIntoConstraints = NO;
106 | scrollView.translatesAutoresizingMaskIntoConstraints = NO;
107 |
108 | [NSLayoutConstraint activateConstraints:@[
109 | [scrollView.topAnchor constraintEqualToAnchor:contentView.topAnchor],
110 | [scrollView.leftAnchor constraintEqualToAnchor:contentView.leftAnchor],
111 | [scrollView.rightAnchor constraintEqualToAnchor:contentView.rightAnchor],
112 | [scrollView.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor]
113 | ]];
114 |
115 | NSTableColumn *column = [[NSTableColumn alloc] init];
116 | column.resizingMask = NSTableColumnAutoresizingMask;
117 | [_tableView addTableColumn:column];
118 |
119 | NSWindow *window = [[NSWindow alloc] initWithContentRect:NSZeroRect styleMask:NSWindowStyleMaskBorderless backing:NSBackingStoreBuffered defer:NO];
120 | window.titleVisibility = NSWindowTitleHidden;
121 | window.hasShadow = YES;
122 | window.opaque = NO;
123 | window.backgroundColor = [NSColor clearColor];
124 | window.contentView = contentView;
125 |
126 | self.window = window;
127 |
128 | return self;
129 | }
130 |
131 | #pragma mark - Public
132 |
133 | - (void)presentWithSuggestions:(NSArray *)suggestions positioningTextView:(NSTextView *)positioningTextView {
134 | self.suggestions = suggestions;
135 |
136 | [self.tableView reloadData];
137 |
138 | if (![self adjustFrameWithPositioningTextView:positioningTextView]) {
139 | return;
140 | }
141 |
142 | if (self.window.isVisible == NO) {
143 | [positioningTextView.window addChildWindow:self.window ordered:NSWindowAbove];
144 |
145 | __weak typeof(self) weakSelf = self;
146 |
147 | if (!self.keyDownMonitor) {
148 | self.keyDownMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown handler:^NSEvent *(NSEvent *event) {
149 | __strong typeof(weakSelf) strongSelf = weakSelf;
150 |
151 | switch (event.keyCode) {
152 | case ZPLEventKeyCodeTab:
153 | case ZPLEventKeyCodeReturn: {
154 | NSInteger selectedRow = strongSelf.tableView.selectedRow;
155 |
156 | if (selectedRow < 0) {
157 | return nil;
158 | }
159 |
160 | [strongSelf.delegate suggestionWindowController:strongSelf didSelectSuggestion:strongSelf.suggestions[selectedRow]];
161 |
162 | return nil;
163 | } break;
164 |
165 | case ZPLEventKeyCodeEscape: {
166 | [strongSelf dismiss];
167 |
168 | return nil;
169 | } break;
170 |
171 | case ZPLEventKeyCodeTopArrow: {
172 | BOOL isCommand = (event.modifierFlags & NSCommandKeyMask) == NSCommandKeyMask;
173 |
174 | NSInteger row = isCommand ? 0 : MAX(strongSelf.tableView.selectedRow - 1, 0);
175 | [strongSelf selectRowAtIndex:row];
176 |
177 | return nil;
178 | } break;
179 |
180 | case ZPLEventKeyCodeBottomArrow: {
181 | BOOL isCommand = (event.modifierFlags & NSCommandKeyMask) == NSCommandKeyMask;
182 |
183 | NSInteger lastRow = strongSelf.suggestions.count - 1;
184 | NSInteger row = isCommand ? lastRow : MIN(strongSelf.tableView.selectedRow + 1, lastRow);
185 | [strongSelf selectRowAtIndex:row];
186 |
187 | return nil;
188 | } break;
189 |
190 | default: {
191 | return event;
192 | } break;
193 | }
194 | }];
195 | }
196 |
197 | if (!self.mouseDownMonitor) {
198 | self.mouseDownMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown handler:^ NSEvent *(NSEvent *event) {
199 | __strong typeof(weakSelf) strongSelf = weakSelf;
200 |
201 | if (strongSelf.window == event.window) {
202 | return event;
203 | }
204 |
205 | if (positioningTextView.window != event.window) {
206 | [strongSelf dismiss];
207 |
208 | return event;
209 | }
210 |
211 | NSPoint point = [positioningTextView convertPoint:event.locationInWindow fromView:nil];
212 |
213 | if (!NSPointInRect(point, positioningTextView.bounds)) {
214 | [strongSelf dismiss];
215 |
216 | return nil;
217 | }
218 |
219 | return event;
220 | }];
221 | }
222 |
223 | positioningTextView.postsFrameChangedNotifications = YES;
224 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(positioningTextViewFrameDidChange:) name:NSViewFrameDidChangeNotification object:positioningTextView];
225 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(parentWindowDidResignKey:) name:NSWindowDidResignKeyNotification object:positioningTextView.window];
226 | }
227 |
228 | [self selectRowAtIndex:0];
229 | }
230 |
231 | - (void)dismiss {
232 | if (self.window.isVisible == NO) {
233 | return;
234 | }
235 |
236 | if (self.keyDownMonitor != nil) {
237 | [NSEvent removeMonitor:self.keyDownMonitor];
238 | self.keyDownMonitor = nil;
239 | }
240 |
241 | if (self.mouseDownMonitor != nil) {
242 | [NSEvent removeMonitor:self.mouseDownMonitor];
243 | self.mouseDownMonitor = nil;
244 | }
245 |
246 | [[NSNotificationCenter defaultCenter] removeObserver:self];
247 |
248 | [self.window.parentWindow removeChildWindow:self.window];
249 | [self.window orderOut:nil];
250 | }
251 |
252 | #pragma mark - Private
253 |
254 | - (BOOL)adjustFrameWithPositioningTextView:(NSTextView *)positioningTextView {
255 | if (self.window == nil || positioningTextView.superview == nil || positioningTextView.window == nil) {
256 | return NO;
257 | }
258 |
259 | CGFloat windowHeight = MIN(self.suggestions.count * ZPLSuggestionCell.height, ZPLSuggestionWindowControllerMaximumWindowSize.height);
260 |
261 | NSRange keywordRange = [self.delegate suggestionWindowController:self keywordRangeForTextView:positioningTextView];
262 | if (keywordRange.location == NSNotFound) {
263 | keywordRange = [positioningTextView selectedRange];
264 | }
265 |
266 | NSRange glyphRange = [[positioningTextView layoutManager] glyphRangeForCharacterRange:keywordRange actualCharacterRange:nil];
267 | NSRect characterRect = [[positioningTextView layoutManager] boundingRectForGlyphRange:glyphRange inTextContainer:[positioningTextView textContainer]];
268 | characterRect = NSInsetRect(characterRect, positioningTextView.textContainerOrigin.x, positioningTextView.textContainerOrigin.y);
269 | NSRect positioningTextViewRect = [positioningTextView convertRect:characterRect toView:nil];
270 | NSRect rect = [positioningTextView.window convertRectToScreen:positioningTextViewRect];
271 |
272 | rect.size.width = ZPLSuggestionWindowControllerMaximumWindowSize.width;
273 | rect.size.height = windowHeight;
274 |
275 | NSRect screenVisibleFrame = positioningTextView.window.screen.visibleFrame;
276 | CGFloat minX = ZPLSuggestionWindowControllerMargin;
277 | CGFloat maxX = NSMaxX(screenVisibleFrame) - ZPLSuggestionWindowControllerMargin;
278 |
279 | if (NSMaxX(rect) > maxX) {
280 | rect.origin.x = maxX - rect.size.width;
281 | } else if (NSMinX(rect) < minX) {
282 | rect.origin.x = minX;
283 | }
284 |
285 | CGFloat rectOriginY = rect.origin.y - windowHeight - ZPLSuggestionWindowControllerMargin;
286 | if (rectOriginY < NSMinY(screenVisibleFrame)) {
287 | rect.origin.y = rect.origin.y + positioningTextViewRect.size.height;
288 | } else {
289 | rect.origin.y = rectOriginY;
290 | }
291 |
292 | [self.window setFrame:rect display:NO];
293 |
294 | return YES;
295 | }
296 |
297 | - (void)selectRowAtIndex:(NSInteger)index {
298 | if (self.suggestions.count == 0) {
299 | return;
300 | }
301 |
302 | NSInteger adjustedIndex = MAX(0, MIN(index, self.suggestions.count - 1));
303 |
304 | [self.tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:adjustedIndex] byExtendingSelection:NO];
305 | [self.tableView scrollRowToVisible:adjustedIndex];
306 | }
307 |
308 | #pragma mark - NSTableViewDataSource
309 |
310 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
311 | return self.suggestions.count;
312 | }
313 |
314 | #pragma mark - ZPLFocusTableViewDelegate
315 |
316 | - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
317 | ZPLSuggestionCell *cell = [tableView makeViewWithIdentifier:[ZPLSuggestionCell reuseIdentifier] owner:self];
318 | if (!cell) {
319 | cell = [[ZPLSuggestionCell alloc] init];
320 | }
321 |
322 | cell.suggestion = self.suggestions[row];
323 |
324 | return cell;
325 | }
326 |
327 | - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
328 | return [ZPLSuggestionCell height];
329 | }
330 |
331 | - (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row {
332 | return [[ZPLRowView alloc] init];
333 | }
334 |
335 | - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row {
336 | return YES;
337 | }
338 |
339 | - (void)tableView:(NSTableView *)tableView didClickRow:(NSInteger)row {
340 | [self.delegate suggestionWindowController:self didSelectSuggestion:self.suggestions[row]];
341 | }
342 |
343 | #pragma mark - Notifications
344 |
345 | - (void)positioningTextViewFrameDidChange:(NSNotification *)notification {
346 | NSTextView *positioningTextView = notification.object;
347 | if (!positioningTextView) {
348 | return;
349 | }
350 |
351 | [self adjustFrameWithPositioningTextView:positioningTextView];
352 | }
353 |
354 | - (void)parentWindowDidResignKey:(NSNotification *)notification {
355 | [self dismiss];
356 | }
357 |
358 | @end
359 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Models/Sketch/ZPLTheme.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLTheme.h
3 | // Autocomplete
4 | //
5 | // Created by K. Berk Cebi on 10/6/18.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | static NSString * const ZPLThemeClassName = @"MSTheme";
30 |
31 | @protocol ZPLTheme
32 |
33 | + (instancetype)sharedTheme;
34 |
35 | @property (readonly, nonatomic) NSColor *inspectorLabelTextColor;
36 | @property (readonly, nonatomic) NSColor *inspectorAccentColor;
37 | @property (readonly, nonatomic) NSColor *layerListBackgroundColor;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Models/ZPLEmoji.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLEmoji.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | extern NSString * const ZPLEmojiAliasSeparator;
30 |
31 | @interface ZPLEmoji : NSObject
32 |
33 | @property (copy, nonatomic) NSString *value;
34 | @property (strong, nonatomic) NSArray *aliases;
35 | @property (strong, nonatomic) NSArray *tags;
36 |
37 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Models/ZPLEmoji.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLEmoji.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLEmoji.h"
28 |
29 | NSString * const ZPLEmojiAliasSeparator = @"_";
30 |
31 | static NSString * const ZPLEmojiValueDictionaryKey = @"emoji";
32 | static NSString * const ZPLEmojiAliasesDictionaryKey = @"aliases";
33 | static NSString * const ZPLEmojiTagsDictionaryKey = @"tags";
34 | static NSString * const ZPLEmojiUnicodeVersionDictionaryKey = @"unicode_version";
35 | static NSString * const ZPLEmojiCategoryDictionaryKey = @"category";
36 | static NSString * const ZPLEmojiFlagsCategoryDictionaryValue = @"Flags";
37 |
38 | static NSString * const ZPLEmojiFlagTag = @"flag";
39 |
40 | static const NSOperatingSystemVersion ZPLEmojiUnicode8OperationSystemVersion = {.majorVersion = 10, .minorVersion = 11, .patchVersion = 5};
41 | static const NSOperatingSystemVersion ZPLEmojiUnicode9OperationSystemVersion = {.majorVersion = 10, .minorVersion = 12, .patchVersion = 2};
42 | static const NSOperatingSystemVersion ZPLEmojiUnicode10OperationSystemVersion = {.majorVersion = 10, .minorVersion = 13, .patchVersion = 1};
43 | static const NSOperatingSystemVersion ZPLEmojiUnicode11OperationSystemVersion = {.majorVersion = 10, .minorVersion = 14, .patchVersion = 1};
44 | static const NSOperatingSystemVersion ZPLEmojiUnicode12OperationSystemVersion = {.majorVersion = 10, .minorVersion = 15, .patchVersion = 1};
45 | static const NSOperatingSystemVersion ZPLEmojiUnicode13OperationSystemVersion = {.majorVersion = 11, .minorVersion = 3, .patchVersion = 0};
46 | static const NSOperatingSystemVersion ZPLEmojiUnicode14OperationSystemVersion = {.majorVersion = 12, .minorVersion = 3, .patchVersion = 0};
47 |
48 | @implementation ZPLEmoji
49 |
50 | + (BOOL)supportsUnicodeVersion:(NSString *)unicodeVersion {
51 | NSMutableArray *supportedUnicodeVersions = [NSMutableArray arrayWithArray:@[@"", @"3.0", @"3.2", @"4.0", @"4.1", @"5.1", @"5.2", @"6.0", @"6.1", @"7.0"]];
52 |
53 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode8OperationSystemVersion]) {
54 | [supportedUnicodeVersions addObject:@"8.0"];
55 | }
56 |
57 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode9OperationSystemVersion]) {
58 | [supportedUnicodeVersions addObject:@"9.0"];
59 | }
60 |
61 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode10OperationSystemVersion]) {
62 | [supportedUnicodeVersions addObject:@"10.0"];
63 | }
64 |
65 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode11OperationSystemVersion]) {
66 | [supportedUnicodeVersions addObject:@"11.0"];
67 | }
68 |
69 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode12OperationSystemVersion]) {
70 | [supportedUnicodeVersions addObject:@"12.0"];
71 | [supportedUnicodeVersions addObject:@"12.1"];
72 | }
73 |
74 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode13OperationSystemVersion]) {
75 | [supportedUnicodeVersions addObject:@"13.0"];
76 | [supportedUnicodeVersions addObject:@"13.1"];
77 | }
78 |
79 | if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:ZPLEmojiUnicode14OperationSystemVersion]) {
80 | [supportedUnicodeVersions addObject:@"14.0"];
81 | }
82 |
83 | return [supportedUnicodeVersions containsObject:unicodeVersion];
84 | }
85 |
86 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary {
87 | self = [super init];
88 | if (!self) {
89 | return nil;
90 | }
91 |
92 | NSString *value = (NSString *)[dictionary objectForKey:ZPLEmojiValueDictionaryKey];
93 | NSArray *aliases = (NSArray *)[dictionary objectForKey:ZPLEmojiAliasesDictionaryKey];
94 | NSArray *tags = (NSArray *)[dictionary objectForKey:ZPLEmojiTagsDictionaryKey];
95 | NSString *unicodeVersion = (NSString *)[dictionary objectForKey:ZPLEmojiUnicodeVersionDictionaryKey];
96 |
97 | if (!value || !aliases || aliases.count == 0 || !unicodeVersion || ![ZPLEmoji supportsUnicodeVersion:unicodeVersion]) {
98 | return nil;
99 | }
100 |
101 | if (!tags) {
102 | tags = [NSArray array];
103 | }
104 |
105 | NSString *category = (NSString *)[dictionary objectForKey:ZPLEmojiCategoryDictionaryKey];
106 |
107 | if ([category isEqualToString:ZPLEmojiFlagsCategoryDictionaryValue] && ![tags containsObject:ZPLEmojiFlagTag]) {
108 | tags = [tags arrayByAddingObject:ZPLEmojiFlagTag];
109 | }
110 |
111 | _value = [value copy];
112 | _aliases = aliases;
113 | _tags = tags;
114 |
115 | return self;
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Models/ZPLSuggestion.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestion.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @class ZPLEmoji;
30 |
31 | @interface ZPLSuggestion : NSObject
32 |
33 | @property (strong, nonatomic) ZPLEmoji *emoji;
34 | @property (copy, nonatomic) NSString *alias;
35 |
36 | - (instancetype)initWithEmoji:(ZPLEmoji *)emoji alias:(NSString *)alias;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Models/ZPLSuggestion.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestion.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLSuggestion.h"
28 |
29 | @implementation ZPLSuggestion
30 |
31 | - (instancetype)initWithEmoji:(ZPLEmoji *)emoji alias:(NSString *)alias {
32 | self = [super init];
33 | if (!self) {
34 | return nil;
35 | }
36 |
37 | _emoji = emoji;
38 | _alias = [alias copy];
39 |
40 | return self;
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLFocusTableView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLFocusTableView.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @protocol ZPLFocusTableViewDelegate;
30 |
31 | @interface ZPLFocusTableView : NSTableView
32 |
33 | @end
34 |
35 | @protocol ZPLFocusTableViewDelegate
36 | @optional
37 |
38 | - (void)tableView:(NSTableView *)tableView didClickRow:(NSInteger)row;
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLFocusTableView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLFocusTableView.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLFocusTableView.h"
28 |
29 | @interface ZPLFocusTableView ()
30 |
31 | @property (strong, nonatomic) NSTrackingArea *trackingArea;
32 |
33 | @end
34 |
35 | @implementation ZPLFocusTableView
36 |
37 | #pragma mark - NSTableView
38 |
39 | - (void)reloadData {
40 | [super reloadData];
41 |
42 | if (!self.window) {
43 | return;
44 | }
45 |
46 | [self reloadSelectionWithMouseLocationInWindow:self.window.mouseLocationOutsideOfEventStream];
47 | }
48 |
49 | #pragma mark - NSResponder
50 |
51 | - (void)updateTrackingAreas {
52 | if (self.trackingArea != nil) {
53 | [self removeTrackingArea:self.trackingArea];
54 | }
55 |
56 | self.trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseMoved | NSTrackingActiveInActiveApp owner:self userInfo:nil];
57 | [self addTrackingArea:self.trackingArea];
58 |
59 | [super updateTrackingAreas];
60 | }
61 |
62 | - (void)mouseDown:(NSEvent *)event {
63 | NSPoint convertedLocation = [self convertPoint:event.locationInWindow toView:nil];
64 | NSInteger row = [self rowAtPoint:convertedLocation];
65 |
66 | id delegate = (id )self.delegate;
67 | if (row >= 0 && [delegate respondsToSelector:@selector(tableView:didClickRow:)]) {
68 | [delegate tableView:self didClickRow:row];
69 | }
70 | }
71 |
72 | - (void)mouseMoved:(NSEvent *)event {
73 | [self reloadSelectionWithMouseLocationInWindow:event.locationInWindow];
74 | }
75 |
76 | #pragma mark - Private
77 |
78 | - (void)reloadSelectionWithMouseLocationInWindow:(NSPoint)mouseLocationInWindow {
79 | NSPoint convertedLocation = [self convertPoint:mouseLocationInWindow toView:nil];
80 | NSInteger row = [self rowAtPoint:convertedLocation];
81 |
82 | if (row < 0 || self.selectedRow == row) {
83 | return;
84 | }
85 |
86 | BOOL shouldSelect = [self.delegate tableView:self shouldSelectRow:row] ?: YES;
87 |
88 | if (shouldSelect) {
89 | [self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
90 | }
91 | }
92 |
93 | @end
94 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLRowView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLRowView.h
3 | // Autocomplete
4 | //
5 | // Created by K. Berk Cebi on 7/9/18.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @interface ZPLRowView : NSTableRowView
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLRowView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLRowView.m
3 | // Autocomplete
4 | //
5 | // Created by K. Berk Cebi on 7/9/18.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLRowView.h"
28 |
29 | #import "NSColor+Autocomplete.h"
30 |
31 | @implementation ZPLRowView
32 |
33 | #pragma mark - ZPLRowView
34 |
35 | - (NSBackgroundStyle)interiorBackgroundStyle {
36 | return self.isSelected ? NSBackgroundStyleDark : NSBackgroundStyleLight;
37 | }
38 |
39 | - (void)drawSelectionInRect:(NSRect)dirtyRect {
40 | [[NSColor zpl_selectionColor] setFill];
41 |
42 | [[NSBezierPath bezierPathWithRect:self.bounds] fill];
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLSuggestionCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionCell.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @class ZPLSuggestion;
30 |
31 | @interface ZPLSuggestionCell : NSTableCellView
32 |
33 | @property (strong, nonatomic) ZPLSuggestion *suggestion;
34 |
35 | + (CGFloat)height;
36 | + (NSString *)reuseIdentifier;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/Views/ZPLSuggestionCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLSuggestionCell.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLSuggestionCell.h"
28 |
29 | #import "ZPLEmoji.h"
30 | #import "ZPLSuggestion.h"
31 | #import "NSColor+Autocomplete.h"
32 |
33 | static const CGFloat ZPLSuggestionCellHeight = 32.0f;
34 | static const CGFloat ZPLSuggestionCellMargin = 8.0f;
35 |
36 | @interface ZPLSuggestionCell ()
37 |
38 | @property (strong, nonatomic) NSTextField *emojiTextField;
39 | @property (strong, nonatomic) NSTextField *aliasTextField;
40 |
41 | @end
42 |
43 | @implementation ZPLSuggestionCell
44 |
45 | + (CGFloat)height {
46 | return ZPLSuggestionCellHeight;
47 | }
48 |
49 | + (NSString *)reuseIdentifier {
50 | return NSStringFromClass([ZPLSuggestionCell class]);
51 | }
52 |
53 | #pragma mark - Initializers
54 |
55 | - (instancetype)initWithFrame:(NSRect)frame {
56 | self = [super initWithFrame:frame];
57 | if (!self) {
58 | return nil;
59 | }
60 |
61 | self.identifier = [[self class] reuseIdentifier];
62 |
63 | _emojiTextField = [[NSTextField alloc] init];
64 | _emojiTextField.bordered = NO;
65 | _emojiTextField.drawsBackground = NO;
66 | _emojiTextField.editable = NO;
67 | _emojiTextField.selectable = NO;
68 | _emojiTextField.usesSingleLineMode = YES;
69 | _emojiTextField.font = [NSFont systemFontOfSize:14.0];
70 | [_emojiTextField setContentCompressionResistancePriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal];
71 | [_emojiTextField setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal];
72 |
73 | _aliasTextField = [[NSTextField alloc] init];
74 | _aliasTextField.bordered = NO;
75 | _aliasTextField.drawsBackground = NO;
76 | _aliasTextField.editable = NO;
77 | _aliasTextField.selectable = NO;
78 | _aliasTextField.usesSingleLineMode = YES;
79 | _aliasTextField.lineBreakMode = NSLineBreakByTruncatingMiddle;
80 | _aliasTextField.alignment = NSTextAlignmentLeft;
81 | _aliasTextField.font = [NSFont systemFontOfSize:11.0];
82 |
83 | NSColor *aliasTextFieldTextColor = [NSColor zpl_textColor];
84 | if (aliasTextFieldTextColor) {
85 | _aliasTextField.textColor = aliasTextFieldTextColor;
86 | }
87 |
88 | [_aliasTextField setContentCompressionResistancePriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
89 | [_aliasTextField setContentHuggingPriority:NSLayoutPriorityDefaultLow forOrientation:NSLayoutConstraintOrientationHorizontal];
90 |
91 | [self addSubview:_emojiTextField];
92 | [self addSubview:_aliasTextField];
93 |
94 | self.translatesAutoresizingMaskIntoConstraints = NO;
95 | _emojiTextField.translatesAutoresizingMaskIntoConstraints = NO;
96 | _aliasTextField.translatesAutoresizingMaskIntoConstraints = NO;
97 |
98 | [NSLayoutConstraint activateConstraints:@[
99 | [_emojiTextField.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:ZPLSuggestionCellMargin],
100 | [_emojiTextField.centerYAnchor constraintEqualToAnchor:self.centerYAnchor],
101 | [_aliasTextField.leftAnchor constraintEqualToAnchor:_emojiTextField.rightAnchor constant:ZPLSuggestionCellMargin],
102 | [_aliasTextField.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:-1.0f * ZPLSuggestionCellMargin],
103 | [_aliasTextField.centerYAnchor constraintEqualToAnchor:self.centerYAnchor]
104 | ]];
105 |
106 | return self;
107 | }
108 |
109 | #pragma mark - Properties
110 |
111 | - (void)setSuggestion:(ZPLSuggestion *)suggestion {
112 | _suggestion = suggestion;
113 |
114 | self.emojiTextField.stringValue = suggestion.emoji.value;
115 | self.aliasTextField.stringValue = suggestion.alias;
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/ZPLAutocompletePluginController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLAutocompletePluginController.h
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import
28 |
29 | @interface ZPLAutocompletePluginController : NSObject
30 |
31 | @property (assign, nonatomic, getter=isEnabled) BOOL enabled;
32 |
33 | + (instancetype)sharedController;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Autocomplete/Sources/ZPLAutocompletePluginController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZPLAutocompletePluginController.m
3 | // Autocomplete
4 | //
5 | // Created by Yigitcan Yurtsever on 29.06.2018.
6 | // Copyright © 2018 Zeplin, Inc.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 | //
26 |
27 | #import "ZPLAutocompletePluginController.h"
28 |
29 | #import "ZPLSuggestionController.h"
30 |
31 | @interface ZPLAutocompletePluginController ()
32 |
33 | @property (strong, nonatomic) ZPLSuggestionController *suggestionController;
34 |
35 | @end
36 |
37 | @implementation ZPLAutocompletePluginController
38 |
39 | #pragma mark - Singleton
40 |
41 | + (instancetype)sharedController {
42 | static dispatch_once_t once;
43 | static id _sharedInstance = nil;
44 | dispatch_once(&once, ^{
45 | _sharedInstance = [[self alloc] init];
46 | });
47 |
48 | return _sharedInstance;
49 | }
50 |
51 | #pragma mark - Properties
52 |
53 | - (void)setEnabled:(BOOL)enabled {
54 | if (_enabled == enabled) {
55 | return;
56 | }
57 |
58 | _enabled = enabled;
59 |
60 | if (enabled) {
61 | self.suggestionController = [[ZPLSuggestionController alloc] init];
62 | } else {
63 | self.suggestionController = nil;
64 | }
65 | }
66 |
67 | @end
68 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Zeplin, Inc.
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 | # Emoji Autocomplete Sketch Plugin
4 | Type `:` followed by the first few letters to autocomplete emojis. 🍒
5 |
6 | ## Installation
7 | - [Download](https://github.com/zeplin/emoji-autocomplete-sketch-plugin/releases/download/v1.3/Emoji.Autocomplete.sketchplugin.zip) latest release, 1.2.
8 | - Unzip, if necessary, and double click `Emoji Autocomplete.sketchplugin`.
9 |
10 | ## Usage
11 | While editing text layers, overrides or layer names, type `:` followed by a few letters to display a list of emojis to autocomplete from. Use the arrow keys or your mouse to select one.
12 |
13 |
14 |
15 | ## License
16 |
17 | Emoji Autocomplete Sketch Plugin is released under the MIT license. See [LICENSE](LICENSE) for details.
18 |
19 | ---
20 |
21 |
22 |
23 | Emoji Autocomplete Sketch Plugin is crafted and maintained by the crew behind [Zeplin](https://zeplin.io). Follow [@zeplin](https://twitter.com/zeplin) on Twitter for project updates and releases.
24 |
--------------------------------------------------------------------------------
/fastlane/Fastfile:
--------------------------------------------------------------------------------
1 | require "fileutils"
2 | require "net/http"
3 | require "tempfile"
4 |
5 | BUILD_DIR = "build"
6 | FRAMEWORK_NAME = "Autocomplete.framework"
7 | PLUGIN_NAME = "Emoji Autocomplete.sketchplugin"
8 |
9 | default_platform(:mac)
10 |
11 | platform :mac do
12 | desc "Install dependencies"
13 | lane :bootstrap do
14 | emojis_uri = URI("https://raw.githubusercontent.com/kardeslik/gemoji/import-emoji-14/db/emoji.json")
15 | emojis_string = Net::HTTP.get(emojis_uri)
16 |
17 | emojis_tempfile = Tempfile.new("emojis")
18 | emojis_tempfile.write(emojis_string)
19 |
20 | resources_dir = File.join("..", "Autocomplete", "Resources")
21 | FileUtils.mkdir_p(resources_dir)
22 |
23 | emojis_path = File.join(resources_dir, "Emojis.plist")
24 |
25 | sh("plutil -convert xml1 #{emojis_tempfile.path} -o #{emojis_path}")
26 |
27 | emojis_tempfile.unlink
28 | end
29 |
30 | desc "Build framework"
31 | lane :build do
32 | xcodebuild(
33 | clean: true,
34 | build: true,
35 | scheme: "Autocomplete",
36 | configuration: "Release",
37 | xcargs: "CONFIGURATION_BUILD_DIR=#{BUILD_DIR}"
38 | )
39 |
40 | File.expand_path(File.join("..", BUILD_DIR))
41 | end
42 |
43 | desc "Package plugin, building framework unless provided"
44 | lane :package do |options|
45 | build_dir = options[:build_dir]
46 | unless build_dir
47 | build_dir = build
48 | end
49 |
50 | plugin_dir = File.join(build_dir, PLUGIN_NAME)
51 | FileUtils.rm_rf(plugin_dir)
52 |
53 | plugin_compressed_path = "#{plugin_dir}.zip"
54 | FileUtils.rm_f(plugin_compressed_path)
55 |
56 | FileUtils.mkdir_p(plugin_dir)
57 |
58 | contents_dir = File.join(plugin_dir, "Contents")
59 | FileUtils.mkdir_p(contents_dir)
60 |
61 | resources_dir = File.join(contents_dir, "Resources")
62 | FileUtils.mkdir_p(resources_dir)
63 |
64 | framework_dir = File.join(build_dir, FRAMEWORK_NAME)
65 | FileUtils.copy_entry(framework_dir, File.join(resources_dir, FRAMEWORK_NAME))
66 |
67 | FileUtils.cp("../plugin/img/icon.png", resources_dir)
68 | FileUtils.cp("../plugin/img/iconRunner.png", resources_dir)
69 | FileUtils.cp("../plugin/img/iconRunnerDark.png", resources_dir)
70 |
71 | sketch_dir = File.join(contents_dir, "Sketch")
72 | FileUtils.mkdir_p(sketch_dir)
73 |
74 | FileUtils.cp("../plugin/manifest.json", sketch_dir)
75 | FileUtils.cp("../plugin/src/index.js", sketch_dir)
76 |
77 | sh("ditto -c -k --rsrc --keepParent \"#{plugin_dir}\" \"#{plugin_compressed_path}\"")
78 |
79 | plugin_dir
80 | end
81 |
82 | desc "Package and install plugin to Sketch"
83 | lane :install do |options|
84 | package_plugin_dir = package(options)
85 | plugin_dir = File.join(Dir.home, "Library", "Application Support", "com.bohemiancoding.sketch3", "Plugins", PLUGIN_NAME)
86 |
87 | FileUtils.rm_f(plugin_dir)
88 | FileUtils.copy_entry(package_plugin_dir, plugin_dir)
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/fastlane/README.md:
--------------------------------------------------------------------------------
1 | fastlane documentation
2 | ================
3 | # Installation
4 |
5 | Make sure you have the latest version of the Xcode command line tools installed:
6 |
7 | ```
8 | xcode-select --install
9 | ```
10 |
11 | Install _fastlane_ using
12 | ```
13 | [sudo] gem install fastlane -NV
14 | ```
15 | or alternatively using `brew cask install fastlane`
16 |
17 | # Available Actions
18 | ## Mac
19 | ### mac bootstrap
20 | ```
21 | fastlane mac bootstrap
22 | ```
23 | Install dependencies
24 | ### mac build
25 | ```
26 | fastlane mac build
27 | ```
28 | Build framework
29 | ### mac package
30 | ```
31 | fastlane mac package
32 | ```
33 | Package plugin, building framework unless provided
34 | ### mac install
35 | ```
36 | fastlane mac install
37 | ```
38 | Package and install plugin to Sketch
39 |
40 | ----
41 |
42 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
43 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
44 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
45 |
--------------------------------------------------------------------------------
/img/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/1bdb1aa3298fee26ca283aa22cdf2bb734da160e/img/demo.gif
--------------------------------------------------------------------------------
/img/iconTransparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/1bdb1aa3298fee26ca283aa22cdf2bb734da160e/img/iconTransparent.png
--------------------------------------------------------------------------------
/img/logo.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/plugin/img/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/1bdb1aa3298fee26ca283aa22cdf2bb734da160e/plugin/img/icon.png
--------------------------------------------------------------------------------
/plugin/img/iconRunner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/1bdb1aa3298fee26ca283aa22cdf2bb734da160e/plugin/img/iconRunner.png
--------------------------------------------------------------------------------
/plugin/img/iconRunnerDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/1bdb1aa3298fee26ca283aa22cdf2bb734da160e/plugin/img/iconRunnerDark.png
--------------------------------------------------------------------------------
/plugin/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Emoji Autocomplete",
3 | "description": "Type “:” followed by the first few letters to autocomplete emojis. 🍒",
4 | "author": "Zeplin, Inc.",
5 | "authorEmail": "support@zeplin.io",
6 | "homepage": "https://github.com/zeplin/emoji-autocomplete-sketch-plugin",
7 | "version": "1.3",
8 | "identifier": "io.zeplin.sketchPlugin.autocomplete",
9 | "appcast": "https://raw.githubusercontent.com/zeplin/emoji-autocomplete-sketch-plugin/master/.appcast.xml",
10 | "icon": "icon.png",
11 | "compatibleVersion": 3,
12 | "bundleVersion": 1,
13 | "commands": [
14 | {
15 | "name": "Handle Actions",
16 | "identifier": "handle-actions",
17 | "script": "index.js",
18 | "handlers": {
19 | "actions": {
20 | "Startup": "onStartup",
21 | "Shutdown": "onShutdown"
22 | }
23 | }
24 | },
25 | {
26 | "name": "About Emoji Autocomplete",
27 | "identifier": "about",
28 | "script": "index.js",
29 | "handler": "onSelectAboutMenuItem",
30 | "icon": "iconRunner.png",
31 | "iconDark": "iconRunnerDark.png",
32 | "description": "Learn more about the Emoji Autocomplete plugin."
33 | }
34 | ],
35 | "menu": {
36 | "items": [
37 | "about"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/plugin/src/index.js:
--------------------------------------------------------------------------------
1 | var REPOSITORY_URL_STRING = "https://github.com/zeplin/emoji-autocomplete-sketch-plugin";
2 |
3 | /**
4 | * Handles startup action.
5 | */
6 | function onStartup(context) {
7 | if (!isFrameworkLoaded()) {
8 | var contentsPath = context.scriptPath.stringByDeletingLastPathComponent().stringByDeletingLastPathComponent();
9 | var resourcesPath = contentsPath.stringByAppendingPathComponent("Resources");
10 |
11 | var result = Mocha.sharedRuntime().loadFrameworkWithName_inDirectory("Autocomplete", resourcesPath);
12 | if (!result) {
13 | var alert = NSAlert.alloc().init();
14 | alert.alertStyle = NSAlertStyleCritical;
15 | alert.messageText = "Loading framework for “Emoji Autocomplete” failed"
16 | alert.informativeText = "Please try disabling and enabling the plugin or restarting Sketch. Contact support@zeplin.io, if the issue continues."
17 |
18 | alert.runModal();
19 |
20 | return;
21 | }
22 | }
23 |
24 | ZPLAutocompletePluginController.sharedController().enabled = true;
25 | }
26 |
27 | /**
28 | * Handles shutdown action.
29 | */
30 | function onShutdown(context) {
31 | if (isFrameworkLoaded()) {
32 | ZPLAutocompletePluginController.sharedController().enabled = false;
33 | }
34 | }
35 |
36 | function isFrameworkLoaded() {
37 | return Boolean(NSClassFromString("ZPLAutocompletePluginController"));
38 | }
39 |
40 | /**
41 | * Handles about menu item.
42 | */
43 | function onSelectAboutMenuItem(context) {
44 | var repositoryUrl = NSURL.URLWithString(REPOSITORY_URL_STRING);
45 |
46 | NSWorkspace.sharedWorkspace().openURL(repositoryUrl);
47 | }
48 |
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Change description
2 |
3 | > Description here
4 |
5 | ## Type of change
6 | - [ ] Bug fix (fixes an issue)
7 | - [ ] New feature (adds functionality)
8 |
9 | ## Related issues
10 |
11 | > Fix [#1]()
12 |
13 | ## Checklists
14 |
15 | ### Development
16 |
17 | - [ ] Lint rules pass locally
18 | - [ ] Application changes have been tested thoroughly
19 | - [ ] Automated tests covering modified code pass
20 |
21 | ### Security
22 |
23 | - [ ] Security impact of change has been considered
24 | - [ ] Code follows company security practices and guidelines
25 |
26 | ### Code review
27 |
28 | - [ ] Pull request has a descriptive title and context useful to a reviewer. Screenshots or screencasts are attached as necessary
29 | - [ ] "Ready for review" label attached and reviewers assigned
30 | - [ ] Changes have been reviewed by at least one other contributor
31 | - [ ] Pull request linked to task tracker where applicable
32 |
--------------------------------------------------------------------------------