diff --git a/languages.ts b/languages.ts index 363de934c..69dd63602 100644 --- a/languages.ts +++ b/languages.ts @@ -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, @@ -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 @@ -258,6 +280,7 @@ export const languageSpecs: LanguageSpec[] = [ 'h', 'hpp', /* Arduino */ 'ino', + /* Objective C */ 'm', ], commentStyle: cStyle, filterDefinitions: cppFilterDefinitions, diff --git a/package.json b/package.json index 3796b8cb8..45b8c792e 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/package/src/handler.ts b/package/src/handler.ts index 80b077f77..a2831759b 100644 --- a/package/src/handler.ts +++ b/package/src/handler.ts @@ -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) diff --git a/samples/objectivec.m b/samples/objectivec.m new file mode 100644 index 000000000..b34bd5623 --- /dev/null +++ b/samples/objectivec.m @@ -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 . +// +// 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 +// . +// +//////////////////////////////////////////////////////////////////////////////// + + +#import "GeoManager.h" +#import +#import +#import +#import + +NSString * BLGeoLockNotification = @"BLGeoLockNotification"; + +@interface GeoManager() + +@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 *_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 *)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 diff --git a/template/src/extension.ts b/template/src/extension.ts index 4c72151e5..17a042ac1 100644 --- a/template/src/extension.ts +++ b/template/src/extension.ts @@ -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, diff --git a/template/yarn.lock b/template/yarn.lock index d6ac1fa06..7843b7c67 100644 --- a/template/yarn.lock +++ b/template/yarn.lock @@ -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" @@ -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== diff --git a/yarn.lock b/yarn.lock index 7dfae045f..7fa29d3d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,10 +12,10 @@ path-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.0.tgz#40702a97af46ae00b0ea6fa8998c0b03c0af160d" integrity sha512-Hkavx/nY4/plImrZPHRk2CL9vpOymZLgEbMNX1U0bjcBL7QN9wODxyx0yaMZURSQaUtSEvDrfAvxa9oPb0at9g== -prettier@^1.18.2: - version "1.18.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" - integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== +prettier@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" + integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== typescript@^3.7.2: version "3.7.5"