Skip to content
This repository was archived by the owner on Mar 18, 2024. It is now read-only.

Commit 31ec357

Browse files
author
M. J. Fromberger
authored
Enable search-based intelligence for Objective C. (#197)
Since Objective C shares header file extensions with C and C++, this commit treats Objective C as a dialect of C++ for the purpose of code intelligence. In addition to adding the .m file extension, it extends the import filter to allow #import and @import directives as well as #include. For native C and C++ code, these extensions will have no material effect. Also: * Update Yarn dependencies. * Formatting fixes from updates to prettier.
1 parent 6f3c44a commit 31ec357

File tree

7 files changed

+310
-28
lines changed

7 files changed

+310
-28
lines changed

languages.ts

+30-7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ const lispStyle: CommentStyle = {
4040
},
4141
}
4242

43+
/**
44+
* Filter a list of candidate definitions to select those likely to be valid
45+
* cross-references for a definition in this file. Accept candidates located in
46+
* files that are a suffix match (ignoring file extension) for some import of
47+
* the current file.
48+
*
49+
* For imports we examine user `#include` and `#import` paths, as well as
50+
* Objective C module `@import` package names. If no candidates match, fall
51+
* back to the raw (unfiltered) results so that the user doesn't get an empty
52+
* response unless there really is nothing.
53+
*/
4354
const cppFilterDefinitions: HandlerArgs['filterDefinitions'] = ({
4455
filePath,
4556
fileContent,
@@ -48,17 +59,28 @@ const cppFilterDefinitions: HandlerArgs['filterDefinitions'] = ({
4859
const imports = fileContent
4960
.split(/\r?\n/)
5061
.map(line => {
51-
const match = /^#include "(.*)"$/.exec(line)
52-
return match ? match[1] : undefined
62+
// Rewrite `@import x.y.z;` as x/y/z to simulate path matching.
63+
// In plain C and C++ files, expect this to be empty.
64+
const matchImport = /^@import (\w+);$/.exec(line)
65+
if (matchImport) {
66+
return matchImport[1].replace(/\./g, '/')
67+
}
68+
69+
// Capture paths from #include and #import directives.
70+
// N.B. Only user paths ("") are captured, not system (<>) paths.
71+
return /^#(include|import) "(.*)"$/.exec(line)?.[2]
5372
})
5473
.filter((x): x is string => Boolean(x))
5574

75+
// Select results whose file path shares a suffix with some import.
76+
// N.B. Paths are compared without file extensions.
5677
const filteredResults = results.filter(result => {
57-
return imports.some(i =>
58-
path
59-
.join(path.parse(result.file).dir, path.parse(result.file).name)
60-
.endsWith(path.join(path.parse(i).dir, path.parse(i).name))
61-
)
78+
const resultParsed = path.parse(result.file)
79+
const candidate = path.join(resultParsed.dir, resultParsed.name)
80+
return imports.some(i => {
81+
const iParsed = path.parse(i)
82+
return candidate.endsWith(path.join(iParsed.dir, iParsed.name))
83+
})
6284
})
6385

6486
return filteredResults.length === 0 ? results : filteredResults
@@ -258,6 +280,7 @@ export const languageSpecs: LanguageSpec[] = [
258280
'h',
259281
'hpp',
260282
/* Arduino */ 'ino',
283+
/* Objective C */ 'm',
261284
],
262285
commentStyle: cStyle,
263286
filterDefinitions: cppFilterDefinitions,

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"license": "MIT",
33
"scripts": {
44
"prettier": "prettier '{package,template,generator}/**/*.{js?(on),ts,yml,md}' languages.ts --write --list-different",
5-
"prettier-check": "npm run prettier -- --write=false"
5+
"prettier-check": "yarn run prettier --write=false"
66
},
77
"devDependencies": {
88
"@sourcegraph/prettierrc": "^3.0.1",
9-
"prettier": "^1.18.2",
9+
"prettier": "^1.19.1",
1010
"typescript": "^3.7.2"
1111
},
1212
"dependencies": {

package/src/handler.ts

+6-9
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,12 @@ export function wrapIndentationInCodeBlocks({
206206
.map(line => ({ line, kind: kindOf(line) }))
207207

208208
function propagateProse(lines: typeof unknownLines): void {
209-
lines.reduce(
210-
(s, line) => {
211-
if (line.kind === undefined && s === 'prose') {
212-
line.kind = 'prose'
213-
}
214-
return line.kind
215-
},
216-
'prose' as LineKind | undefined
217-
)
209+
lines.reduce((s, line) => {
210+
if (line.kind === undefined && s === 'prose') {
211+
line.kind = 'prose'
212+
}
213+
return line.kind
214+
}, 'prose' as LineKind | undefined)
218215
}
219216

220217
propagateProse(unknownLines)

samples/objectivec.m

+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
//////////////////////////////////////////////////////////////////////////////////
2+
//
3+
// B L I N K
4+
//
5+
// Copyright (C) 2016-2018 Blink Mobile Shell Project
6+
//
7+
// This file is part of Blink.
8+
//
9+
// Blink is free software: you can redistribute it and/or modify
10+
// it under the terms of the GNU General Public License as published by
11+
// the Free Software Foundation, either version 3 of the License, or
12+
// (at your option) any later version.
13+
//
14+
// Blink is distributed in the hope that it will be useful,
15+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
// GNU General Public License for more details.
18+
//
19+
// You should have received a copy of the GNU General Public License
20+
// along with Blink. If not, see <http://www.gnu.org/licenses/>.
21+
//
22+
// In addition, Blink is also subject to certain additional terms under
23+
// GNU GPL version 3 section 7.
24+
//
25+
// You should have received a copy of these additional terms immediately
26+
// following the terms and conditions of the GNU General Public License
27+
// which accompanied the Blink Source Code. If not, see
28+
// <http://www.github.com/blinksh/blink>.
29+
//
30+
////////////////////////////////////////////////////////////////////////////////
31+
32+
33+
#import "GeoManager.h"
34+
#import <CoreLocation/CoreLocation.h>
35+
#import <ImageIO/ImageIO.h>
36+
#import <UIKit/UIKit.h>
37+
#import <UserNotifications/UserNotifications.h>
38+
39+
NSString * BLGeoLockNotification = @"BLGeoLockNotification";
40+
41+
@interface GeoManager() <CLLocationManagerDelegate>
42+
43+
@end
44+
45+
// https://gist.github.com/rsattar/b06060df7ea293b398d1
46+
NSDictionary *__locationToJson(CLLocation * location) {
47+
NSMutableDictionary *gps = [NSMutableDictionary dictionary];
48+
49+
// Example:
50+
/*
51+
"{GPS}" = {
52+
Altitude = "41.28771929824561";
53+
AltitudeRef = 0;
54+
DateStamp = "2014:07:21";
55+
ImgDirection = "68.2140221402214";
56+
ImgDirectionRef = T;
57+
Latitude = "37.74252";
58+
LatitudeRef = N;
59+
Longitude = "122.42035";
60+
LongitudeRef = W;
61+
TimeStamp = "15:53:24";
62+
};
63+
*/
64+
65+
// GPS tag version
66+
// According to http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf,
67+
// this value is 2.3.0.0
68+
[gps setObject:@"2.3.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion];
69+
70+
// Time and date must be provided as strings, not as an NSDate object
71+
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
72+
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
73+
formatter.dateFormat = @"HH:mm:ss.SSSSSS";
74+
gps[(NSString *)kCGImagePropertyGPSTimeStamp] = [formatter stringFromDate:location.timestamp];
75+
formatter.dateFormat = @"yyyy:MM:dd";
76+
gps[(NSString *)kCGImagePropertyGPSDateStamp] = [formatter stringFromDate:location.timestamp];
77+
78+
// Latitude
79+
CLLocationDegrees latitude = location.coordinate.latitude;
80+
gps[(NSString *)kCGImagePropertyGPSLatitudeRef] = (latitude < 0) ? @"S" : @"N";
81+
gps[(NSString *)kCGImagePropertyGPSLatitude] = @(fabs(latitude));
82+
83+
// Longitude
84+
CLLocationDegrees longitude = location.coordinate.longitude;
85+
gps[(NSString *)kCGImagePropertyGPSLongitudeRef] = (longitude < 0) ? @"W" : @"E";
86+
gps[(NSString *)kCGImagePropertyGPSLongitude] = @(fabs(longitude));
87+
88+
// Degree of Precision
89+
gps[(NSString *)kCGImagePropertyGPSDOP] = @(location.horizontalAccuracy);
90+
91+
// Altitude
92+
CLLocationDistance altitude = location.altitude;
93+
if (!isnan(altitude)) {
94+
gps[(NSString *)kCGImagePropertyGPSAltitudeRef] = (altitude < 0) ? @(1) : @(0);
95+
gps[(NSString *)kCGImagePropertyGPSAltitude] = @(fabs(altitude));
96+
}
97+
98+
// Speed, must be converted from m/s to km/h
99+
if (location.speed >= 0) {
100+
gps[(NSString *)kCGImagePropertyGPSSpeedRef] = @"K";
101+
gps[(NSString *)kCGImagePropertyGPSSpeed] = @(location.speed * (3600.0/1000.0));
102+
}
103+
104+
// Direction of movement
105+
if (location.course >= 0) {
106+
gps[(NSString *)kCGImagePropertyGPSTrackRef] = @"T";
107+
gps[(NSString *)kCGImagePropertyGPSTrack] = @(location.course);
108+
}
109+
110+
111+
return gps;
112+
}
113+
114+
@implementation GeoManager {
115+
CLLocationManager * _locManager;
116+
NSMutableArray<CLLocation *> *_recentLocations;
117+
NSNumber *_lockDistanceInMeters;
118+
CLLocation *_lockCenter;
119+
}
120+
121+
- (instancetype)init {
122+
if (self = [super init]) {
123+
_recentLocations = [[NSMutableArray alloc] init];
124+
_locManager = [[CLLocationManager alloc] init];
125+
_locManager.delegate = self;
126+
_traking = NO;
127+
}
128+
return self;
129+
}
130+
131+
+ (GeoManager *)shared {
132+
static GeoManager *manager = nil;
133+
static dispatch_once_t onceToken;
134+
dispatch_once(&onceToken, ^{
135+
manager = [[self alloc] init];
136+
});
137+
return manager;
138+
}
139+
140+
- (void)authorize {
141+
[_locManager requestWhenInUseAuthorization];
142+
}
143+
144+
- (void)start {
145+
if (_traking) {
146+
return;
147+
}
148+
149+
_locManager.desiredAccuracy = 100000;
150+
_locManager.allowsBackgroundLocationUpdates = YES;
151+
_locManager.pausesLocationUpdatesAutomatically = NO;
152+
[_locManager startUpdatingLocation];
153+
154+
_traking = YES;
155+
}
156+
157+
- (void)lockInDistance:(NSNumber *)meters {
158+
if (_traking) {
159+
return;
160+
}
161+
162+
_lockDistanceInMeters = meters;
163+
_locManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
164+
_locManager.allowsBackgroundLocationUpdates = YES;
165+
_locManager.pausesLocationUpdatesAutomatically = NO;
166+
[_locManager startUpdatingLocation];
167+
168+
_traking = YES;
169+
}
170+
171+
- (void)_postLockNotifications {
172+
[[NSNotificationCenter defaultCenter] postNotificationName:BLGeoLockNotification object:nil];
173+
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
174+
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
175+
if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
176+
return;
177+
}
178+
if (settings.alertSetting != UNNotificationSettingEnabled) {
179+
return;
180+
}
181+
182+
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
183+
content.title = @"Geo lock";
184+
content.body = @"Your device get out of geo range lock.\nAll session are terminated.";
185+
UNNotificationRequest *req = [UNNotificationRequest requestWithIdentifier:@"geo.lock" content:content trigger:nil];
186+
187+
[center addNotificationRequest:req withCompletionHandler:^(NSError * _Nullable error) {
188+
189+
}];
190+
}];
191+
}
192+
193+
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
194+
[_recentLocations addObjectsFromArray:locations];
195+
196+
if (_lockDistanceInMeters) {
197+
198+
if (_lockCenter) {
199+
CLLocationDistance distance = [_lockCenter distanceFromLocation:[_recentLocations lastObject]];
200+
if (distance > _lockDistanceInMeters.doubleValue) {
201+
[self stop];
202+
[self _postLockNotifications];
203+
}
204+
} else if (_recentLocations.count > 10) {
205+
_lockCenter = [_recentLocations lastObject];
206+
}
207+
}
208+
209+
int maxHistory = 200;
210+
if (_recentLocations.count > maxHistory) {
211+
[_recentLocations removeObjectsInRange:NSMakeRange(0, _recentLocations.count - maxHistory)];
212+
}
213+
}
214+
215+
- (CLLocation * __nullable)lastLocation {
216+
return [_recentLocations lastObject];
217+
}
218+
219+
- (NSString *)currentJSON {
220+
CLLocation * loc = [_recentLocations lastObject];
221+
if (!loc) {
222+
return @"{}";
223+
}
224+
225+
NSData *data = [NSJSONSerialization dataWithJSONObject:__locationToJson(loc) options:NSJSONWritingPrettyPrinted error:nil];
226+
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
227+
}
228+
229+
- (NSString *)lastJSONN:(int)n {
230+
if (n <= 0) {
231+
n = 1;
232+
}
233+
NSMutableArray *result = [[NSMutableArray alloc] init];
234+
NSArray *locs = [_recentLocations copy];
235+
if (locs.count == 0) {
236+
return @"[]";
237+
}
238+
int i = (int)locs.count;
239+
while (n > 0 && i > 0) {
240+
i--;
241+
n--;
242+
243+
CLLocation *loc = locs[i];
244+
NSDictionary *json = __locationToJson(loc);
245+
[result addObject: json];
246+
}
247+
248+
NSData *data = [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil];
249+
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
250+
}
251+
252+
- (void)stop {
253+
if (_lockCenter) {
254+
[_recentLocations removeAllObjects];
255+
}
256+
_lockDistanceInMeters = nil;
257+
_lockCenter = nil;
258+
[_locManager stopUpdatingLocation];
259+
_traking = NO;
260+
}
261+
262+
@end

template/src/extension.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,9 @@ export function activate(ctx: sourcegraph.ExtensionContext = DUMMY_CTX): void {
7272
// Unconditionally get search references and append them with
7373
// precise results because LSIF data might be sparse. Remove any
7474
// search-based result that occurs in a file with an LSIF result.
75-
const searchReferences = (await handler.references(
76-
doc,
77-
pos
78-
)).filter(fuzzyRef => !lsifFiles.has(file(fuzzyRef)))
75+
const searchReferences = (
76+
await handler.references(doc, pos)
77+
).filter(fuzzyRef => !lsifFiles.has(file(fuzzyRef)))
7978

8079
return [
8180
...lsifValues,

template/yarn.lock

+3-2
Original file line numberDiff line numberDiff line change
@@ -761,10 +761,11 @@
761761
integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
762762

763763
"@sourcegraph/basic-code-intel@../package":
764-
version "7.0.9"
764+
version "10.0.0"
765765
dependencies:
766766
lodash "^4.17.11"
767767
rxjs "^6.3.3"
768+
semver "^6.3.0"
768769
sourcegraph "^23.0.1"
769770
vscode-languageserver-types "^3.14.0"
770771

@@ -5405,7 +5406,7 @@ saxes@^3.1.9:
54055406
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
54065407
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
54075408

5408-
semver@^6.0.0:
5409+
semver@^6.0.0, semver@^6.3.0:
54095410
version "6.3.0"
54105411
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
54115412
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==

0 commit comments

Comments
 (0)