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

Enable search-based intelligence for Objective C. #197

Merged
merged 4 commits into from
Jan 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ const lispStyle: CommentStyle = {
},
}

/**
* Filter a list of candidate definitions to select those likely to be valid
* cross-references for a definition in this file. Accept candidates located in
* files that are a suffix match (ignoring file extension) for some import of
* the current file.
*
* For imports we examine user `#include` and `#import` paths, as well as
* Objective C module `@import` package names. If no candidates match, fall
* back to the raw (unfiltered) results so that the user doesn't get an empty
* response unless there really is nothing.
*/
const cppFilterDefinitions: HandlerArgs['filterDefinitions'] = ({
filePath,
fileContent,
Expand All @@ -48,17 +59,28 @@ const cppFilterDefinitions: HandlerArgs['filterDefinitions'] = ({
const imports = fileContent
.split(/\r?\n/)
.map(line => {
const match = /^#include "(.*)"$/.exec(line)
return match ? match[1] : undefined
// Rewrite `@import x.y.z;` as x/y/z to simulate path matching.
// In plain C and C++ files, expect this to be empty.
const matchImport = /^@import (\w+);$/.exec(line)
if (matchImport) {
return matchImport[1].replace(/\./g, '/')
}

// Capture paths from #include and #import directives.
// N.B. Only user paths ("") are captured, not system (<>) paths.
return /^#(include|import) "(.*)"$/.exec(line)?.[2]
})
.filter((x): x is string => Boolean(x))

// Select results whose file path shares a suffix with some import.
// N.B. Paths are compared without file extensions.
const filteredResults = results.filter(result => {
return imports.some(i =>
path
.join(path.parse(result.file).dir, path.parse(result.file).name)
.endsWith(path.join(path.parse(i).dir, path.parse(i).name))
)
const resultParsed = path.parse(result.file)
const candidate = path.join(resultParsed.dir, resultParsed.name)
return imports.some(i => {
const iParsed = path.parse(i)
return candidate.endsWith(path.join(iParsed.dir, iParsed.name))
})
})

return filteredResults.length === 0 ? results : filteredResults
Expand Down Expand Up @@ -258,6 +280,7 @@ export const languageSpecs: LanguageSpec[] = [
'h',
'hpp',
/* Arduino */ 'ino',
/* Objective C */ 'm',
],
commentStyle: cStyle,
filterDefinitions: cppFilterDefinitions,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"license": "MIT",
"scripts": {
"prettier": "prettier '{package,template,generator}/**/*.{js?(on),ts,yml,md}' languages.ts --write --list-different",
"prettier-check": "npm run prettier -- --write=false"
"prettier-check": "yarn run prettier --write=false"
},
"devDependencies": {
"@sourcegraph/prettierrc": "^3.0.1",
"prettier": "^1.18.2",
"prettier": "^1.19.1",
"typescript": "^3.7.2"
},
"dependencies": {
Expand Down
15 changes: 6 additions & 9 deletions package/src/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,12 @@ export function wrapIndentationInCodeBlocks({
.map(line => ({ line, kind: kindOf(line) }))

function propagateProse(lines: typeof unknownLines): void {
lines.reduce(
(s, line) => {
if (line.kind === undefined && s === 'prose') {
line.kind = 'prose'
}
return line.kind
},
'prose' as LineKind | undefined
)
lines.reduce((s, line) => {
if (line.kind === undefined && s === 'prose') {
line.kind = 'prose'
}
return line.kind
}, 'prose' as LineKind | undefined)
}

propagateProse(unknownLines)
Expand Down
262 changes: 262 additions & 0 deletions samples/objectivec.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
//////////////////////////////////////////////////////////////////////////////////
//
// B L I N K
//
// Copyright (C) 2016-2018 Blink Mobile Shell Project
//
// This file is part of Blink.
//
// Blink is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Blink is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Blink. If not, see <http://www.gnu.org/licenses/>.
//
// In addition, Blink is also subject to certain additional terms under
// GNU GPL version 3 section 7.
//
// You should have received a copy of these additional terms immediately
// following the terms and conditions of the GNU General Public License
// which accompanied the Blink Source Code. If not, see
// <http://www.github.com/blinksh/blink>.
//
////////////////////////////////////////////////////////////////////////////////


#import "GeoManager.h"
#import <CoreLocation/CoreLocation.h>
#import <ImageIO/ImageIO.h>
#import <UIKit/UIKit.h>
#import <UserNotifications/UserNotifications.h>

NSString * BLGeoLockNotification = @"BLGeoLockNotification";

@interface GeoManager() <CLLocationManagerDelegate>

@end

// https://gist.github.com/rsattar/b06060df7ea293b398d1
NSDictionary *__locationToJson(CLLocation * location) {
NSMutableDictionary *gps = [NSMutableDictionary dictionary];

// Example:
/*
"{GPS}" = {
Altitude = "41.28771929824561";
AltitudeRef = 0;
DateStamp = "2014:07:21";
ImgDirection = "68.2140221402214";
ImgDirectionRef = T;
Latitude = "37.74252";
LatitudeRef = N;
Longitude = "122.42035";
LongitudeRef = W;
TimeStamp = "15:53:24";
};
*/

// GPS tag version
// According to http://www.cipa.jp/std/documents/e/DC-008-2012_E.pdf,
// this value is 2.3.0.0
[gps setObject:@"2.3.0.0" forKey:(NSString *)kCGImagePropertyGPSVersion];

// Time and date must be provided as strings, not as an NSDate object
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"];
formatter.dateFormat = @"HH:mm:ss.SSSSSS";
gps[(NSString *)kCGImagePropertyGPSTimeStamp] = [formatter stringFromDate:location.timestamp];
formatter.dateFormat = @"yyyy:MM:dd";
gps[(NSString *)kCGImagePropertyGPSDateStamp] = [formatter stringFromDate:location.timestamp];

// Latitude
CLLocationDegrees latitude = location.coordinate.latitude;
gps[(NSString *)kCGImagePropertyGPSLatitudeRef] = (latitude < 0) ? @"S" : @"N";
gps[(NSString *)kCGImagePropertyGPSLatitude] = @(fabs(latitude));

// Longitude
CLLocationDegrees longitude = location.coordinate.longitude;
gps[(NSString *)kCGImagePropertyGPSLongitudeRef] = (longitude < 0) ? @"W" : @"E";
gps[(NSString *)kCGImagePropertyGPSLongitude] = @(fabs(longitude));

// Degree of Precision
gps[(NSString *)kCGImagePropertyGPSDOP] = @(location.horizontalAccuracy);

// Altitude
CLLocationDistance altitude = location.altitude;
if (!isnan(altitude)) {
gps[(NSString *)kCGImagePropertyGPSAltitudeRef] = (altitude < 0) ? @(1) : @(0);
gps[(NSString *)kCGImagePropertyGPSAltitude] = @(fabs(altitude));
}

// Speed, must be converted from m/s to km/h
if (location.speed >= 0) {
gps[(NSString *)kCGImagePropertyGPSSpeedRef] = @"K";
gps[(NSString *)kCGImagePropertyGPSSpeed] = @(location.speed * (3600.0/1000.0));
}

// Direction of movement
if (location.course >= 0) {
gps[(NSString *)kCGImagePropertyGPSTrackRef] = @"T";
gps[(NSString *)kCGImagePropertyGPSTrack] = @(location.course);
}


return gps;
}

@implementation GeoManager {
CLLocationManager * _locManager;
NSMutableArray<CLLocation *> *_recentLocations;
NSNumber *_lockDistanceInMeters;
CLLocation *_lockCenter;
}

- (instancetype)init {
if (self = [super init]) {
_recentLocations = [[NSMutableArray alloc] init];
_locManager = [[CLLocationManager alloc] init];
_locManager.delegate = self;
_traking = NO;
}
return self;
}

+ (GeoManager *)shared {
static GeoManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
});
return manager;
}

- (void)authorize {
[_locManager requestWhenInUseAuthorization];
}

- (void)start {
if (_traking) {
return;
}

_locManager.desiredAccuracy = 100000;
_locManager.allowsBackgroundLocationUpdates = YES;
_locManager.pausesLocationUpdatesAutomatically = NO;
[_locManager startUpdatingLocation];

_traking = YES;
}

- (void)lockInDistance:(NSNumber *)meters {
if (_traking) {
return;
}

_lockDistanceInMeters = meters;
_locManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_locManager.allowsBackgroundLocationUpdates = YES;
_locManager.pausesLocationUpdatesAutomatically = NO;
[_locManager startUpdatingLocation];

_traking = YES;
}

- (void)_postLockNotifications {
[[NSNotificationCenter defaultCenter] postNotificationName:BLGeoLockNotification object:nil];
UNUserNotificationCenter * center = [UNUserNotificationCenter currentNotificationCenter];
[center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
if (settings.authorizationStatus != UNAuthorizationStatusAuthorized) {
return;
}
if (settings.alertSetting != UNNotificationSettingEnabled) {
return;
}

UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = @"Geo lock";
content.body = @"Your device get out of geo range lock.\nAll session are terminated.";
UNNotificationRequest *req = [UNNotificationRequest requestWithIdentifier:@"geo.lock" content:content trigger:nil];

[center addNotificationRequest:req withCompletionHandler:^(NSError * _Nullable error) {

}];
}];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
[_recentLocations addObjectsFromArray:locations];

if (_lockDistanceInMeters) {

if (_lockCenter) {
CLLocationDistance distance = [_lockCenter distanceFromLocation:[_recentLocations lastObject]];
if (distance > _lockDistanceInMeters.doubleValue) {
[self stop];
[self _postLockNotifications];
}
} else if (_recentLocations.count > 10) {
_lockCenter = [_recentLocations lastObject];
}
}

int maxHistory = 200;
if (_recentLocations.count > maxHistory) {
[_recentLocations removeObjectsInRange:NSMakeRange(0, _recentLocations.count - maxHistory)];
}
}

- (CLLocation * __nullable)lastLocation {
return [_recentLocations lastObject];
}

- (NSString *)currentJSON {
CLLocation * loc = [_recentLocations lastObject];
if (!loc) {
return @"{}";
}

NSData *data = [NSJSONSerialization dataWithJSONObject:__locationToJson(loc) options:NSJSONWritingPrettyPrinted error:nil];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

- (NSString *)lastJSONN:(int)n {
if (n <= 0) {
n = 1;
}
NSMutableArray *result = [[NSMutableArray alloc] init];
NSArray *locs = [_recentLocations copy];
if (locs.count == 0) {
return @"[]";
}
int i = (int)locs.count;
while (n > 0 && i > 0) {
i--;
n--;

CLLocation *loc = locs[i];
NSDictionary *json = __locationToJson(loc);
[result addObject: json];
}

NSData *data = [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:nil];
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

- (void)stop {
if (_lockCenter) {
[_recentLocations removeAllObjects];
}
_lockDistanceInMeters = nil;
_lockCenter = nil;
[_locManager stopUpdatingLocation];
_traking = NO;
}

@end
7 changes: 3 additions & 4 deletions template/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,9 @@ export function activate(ctx: sourcegraph.ExtensionContext = DUMMY_CTX): void {
// Unconditionally get search references and append them with
// precise results because LSIF data might be sparse. Remove any
// search-based result that occurs in a file with an LSIF result.
const searchReferences = (await handler.references(
doc,
pos
)).filter(fuzzyRef => !lsifFiles.has(file(fuzzyRef)))
const searchReferences = (
await handler.references(doc, pos)
).filter(fuzzyRef => !lsifFiles.has(file(fuzzyRef)))

return [
...lsifValues,
Expand Down
5 changes: 3 additions & 2 deletions template/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -761,10 +761,11 @@
integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==

"@sourcegraph/basic-code-intel@../package":
version "7.0.9"
version "10.0.0"
dependencies:
lodash "^4.17.11"
rxjs "^6.3.3"
semver "^6.3.0"
sourcegraph "^23.0.1"
vscode-languageserver-types "^3.14.0"

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

semver@^6.0.0:
semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
Expand Down
Loading