Så här skapar du en Xcode Source Editor Extension

Vad du ska skapa

Introduktion

Xcode är den viktigaste IDE (Integrated Development Environment) som används av tusentals och tusentals utvecklare varje dag. Det är ett fantastiskt verktyg, men ibland vill du anpassa några av dess funktioner och beteenden för att bättre passa ditt arbetsflöde.

Fram till Xcode 7 var det möjligt att injicera kod i Xcode vid körning för att skapa plugins. Plugins kan skickas in och distribueras via en bra app som heter Alcatraz. Detta är inte längre möjligt i Xcode 8.

Xcode 8 validerar varje bibliotek och bunt för att förhindra att skadlig kod körs utan ditt tillstånd. När Xcode startas laddas inte tidigare installerade plugins med Alcatraz längre. Inte allt är förlorat, men Apple meddelade också vid WWDC möjligheten att utveckla Xcode källa redaktörstillägg så att alla kan utöka befintliga källredigeringsfunktioner. Låt oss ta en titt på vad vi kan uppnå med sådana tillägg.

1. Komma igång

Xcode 8-källedirektörstillägg är ett första steg i rätt riktning. Om du har arbetat med Xcode ett tag har du kanske befunnit dig i en situation där du önskade att en viss uppgift skulle kunna automatiseras inom Xcode. Utvidgningar av källredigerare tillåter program från tredje part att ändra en källfil, vilket är precis vad du behöver för att påskynda ditt arbetsflöde.

För tillfället kan utvidgningar endast interagera med källkoden. Det betyder att inte alla plugin som finns tillgängliga via Alcatraz kan ersättas av en källredigerare. Men vem vet vad framtiden ger.

Det är viktigt att förstå att varje förlängning måste finnas i en macOS-app. Du kan till exempel lägga till inställningar och förklaringar om vad förlängningen gör i MacOS-appen och distribuera den via Mac App Store. Observera också att varje anknytning körs i en separat process. Om förlängningen kraschar kommer den inte att krascha Xcode. Istället kommer det att visas ett meddelande om att tillägget inte kunde slutföra sitt arbete.

Dessutom förlängningar har inget användargränssnitt och de kan bara ändra koden direkt när användaren åberopar ditt kommando. De kan exempelvis inte köra i bakgrunden.

Jag rekommenderar att du tittar på WWDC 2016-sessionen om källredigeringsutökningar. Det förklarar inte bara hur man kommer igång med att utveckla Xcode Source Editor-tillägg, det visar också tips och genvägar för att påskynda din utveckling.

2. Översikt

I denna handledning kommer vi att utveckla en förlängning som rensar stängningssyntaxen i Swift. Xcode autocompletterar en stängningssyntax med parenteserna, men de kan utelämnas för korthet. Det här är en uppgift som enkelt kan automatiseras genom att lägga in den i en källredigerare.

Den kortare förklaringen av vad vi ska utveckla är en förlängning som förvandlar eventuell tillslutning till den enklare och renare syntaxen. Ta en titt på exemplet nedan.

// Före session.dataTask (med: url) (data, svar, fel) i // Efter session.dataTask (med: url) data, svar, fel i

3. Projektinställningar

Det är självklart att den här handledningen kräver Xcode 8. Du kan ladda ner den från Apples utvecklarwebbplats. Den körs både på OS X 10.11 och MacOS 10.12.

Skapa en ny OS X projekt av typ Kakaoapplikation och ge det namnet CleanClosureSyntax. Se till att du har satt språk för projektet till Snabb. Vi kommer att använda det nya Swift 3 syntax i denna handledning.

Vi kommer att lämna macOS-appen tom för nu och vi kan fokusera på att skapa Xcode Source-redigeringsutvidgningen. Från Fil meny, välj Ny> Mål ... . Välj i vänster sidofält OS X och välj Xcode Source Editor Extension från listan.

Klick Nästa och ställa in produktnamn till Rengöringsmedel. Ett nytt mål kommer att skapas för dig. Klick Aktivera om Xcode frågar dig om den nyskapade Schema bör aktiveras.

4. Projektstruktur

Låt oss först analysera vilken Xcode som just skapats för oss. Expandera Rengöringsmedel mapp för att se innehållet.

Vi kommer inte att ändra SourceEditorExtension.swift i denna handledning, men det kan användas för att ytterligare anpassa din förlängning. De extensionDidFinishLaunching () Metoden heter så snart förlängningen är igång så att du kan utföra eventuell initialisering om det behövs. De commandDefinitions egendom getter kan användas om du vill visa eller dölja vissa kommandon dynamiskt.

SourceEditorCommand.swift är hörelsen av förlängningen. Den här filen är där du kommer att implementera logiken för förlängningen. De utföra (med: completionHandler :) Metoden heter när användaren startar din förlängning. De XCSourceEditorCommandInvocation objekt innehåller a buffert egenskap, som används för att komma åt källkoden i den aktuella valda filen. Slutföringshanteraren ska kallas med värde noll om allt gick bra, annars skicka det en NSError exempel.

5. Genomförande av förlängningen

Nu när projektet innehåller alla nödvändiga mål är vi redo att börja skriva ut förlängningen. För att återskapa vill vi ta bort parenteserna från alla stängningar i en Swift-fil. Detta kan göras i tre steg:

  • hitta de linjer som innehåller en stängning
  • Ta bort de två parenteserna från den aktuella linjen
  • ersätt den modifierade linjen

Låt oss börja.

Vi kan använda en regex (regelbundet uttryck) för att analysera varje rad kod och se om den innehåller en nedläggning. Du kan referera till Akiels handledning om Swift och reguljära uttryck om du vill lära dig mer om reguljära uttryck. Du kan använda RegExr för att testa dina vanliga uttryck. Ta en titt på följande skärmdump för att se hur jag testade min regex.

Öppna SourceEditorCommand.swift och modifiera utföra (med: completionHandler :) metod att se så här ut:

func perform (med invocation: XCSourceEditorCommandInvocation, completionHandler: (NSError?) -> Void) -> Radera var updatedLineIndexes = [Int] () // 1. Hitta rader som innehåller en syntax för linjenIndex i 0 ... < invocation.buffer.lines.count  let line = invocation.buffer.lines[lineIndex] as! NSString do  let regex = try RegularExpression(pattern: "\\.*\\(.+\\).+in", options: .caseInsensitive) let range = NSRange(0… < line.length) let results = regex.matches(in: line as String, options: .reportProgress, range: range) // 2. When a closure is found, clean up its syntax _ = results.map  result in let cleanLine = line.remove(characters: ["(", ")"], in: result.range) updatedLineIndexes.append(lineIndex) invocation.buffer.lines[lineIndex] = cleanLine   catch  completionHandler(error as NSError)   // 3. If at least a line was changed, create an array of changes and pass it to the buffer selections if !updatedLineIndexes.isEmpty  let updatedSelections: [XCSourceTextRange] = updatedLineIndexes.map  lineIndex in let lineSelection = XCSourceTextRange() lineSelection.start = XCSourceTextPosition(line: lineIndex, column: 0) lineSelection.end = XCSourceTextPosition(line: lineIndex, column: 0) return lineSelection  invocation.buffer.selections.setArray(updatedSelections)  completionHandler(nil) 

Hitta linjer med stängningssyntax

Vi skapar och skapar en mängd int värden som kommer att innehålla linjens index för de modifierade linjerna. Detta beror på att vi inte vill ersätta alla linjer. Vi vill bara ersätta de linjer som vi ändrar.

Vi räknar upp över alla linjer i invocation.buffer objekt och vi försöker hitta en matchning för Vanligt uttryck objekt. Om jag tar bort escaping-tecknen från regex ser det ut som följande:

. * (. +). + I

Denna regex matchar när en sträng har följande egenskaper:

  • Den har en lockig öppen konsol (), som följs av 0 eller flera tecken, förutom ett nytt rad tecken (\ n).
  • En öppen parentes (() måste hittas igen, följt av 0 eller flera tecken. Denna del ska innehålla parametrarna för stängningen.
  • Vi behöver då hitta en slutlig parentes ()) följt av 0 eller fler tecken, vilka är de valfria returtyperna.
  • Slutligen, den i sökord ska hittas.

Om Vanligt uttryck objekt misslyckas med att hitta en matchning (till exempel om regexen inte är giltig), kallar vi completionHandler med felet som en parameter. Om en sträng som matchar alla dessa villkor finns på en rad har vi korrekt lokaliserat en stängning.

Rensa upp syntaxen

När en matchning hittas kallar vi en verktygsmetod på NSString som tar bort parenteserna. Vi måste också passera inom matchområdet för att undvika att ta bort några andra parentes utanför stängningen.

Uppdatera linjer

Den sista delen av koden kontrollerar att åtminstone en rad har ändrats. Om detta är sant, vi ringer setArray () att ersätta de nya linjerna och de korrekta indexerna. Avslutningsbehandlaren heter med värdet noll så att Xcode vet att allt gick bra.

Vi måste fortfarande implementera ta bort (tecken: range :) metod på NSString. Låt oss lägga till den här utvidgningen längst upp i filen.

förlängning NSString // Ta bort de angivna tecknen i intervallet func ta bort (tecken: [Tecken] inom intervall: NSRange) -> NSString var cleanString = själv för karaktärs tecken cleanString = cleanString.replacingOccurrences (av: String ), med: "", alternativ: .caseInsensensearch, range: range) returnera cleanString

Denna metod kallar replacingOccurrences (av: med: range :) på NSString för varje tecken som vi vill ta bort.

6. Testning

Xcode 8 kommer med en bra lösning för att testa förlängningar. Först av allt, om du kör OS X 10.11 El Capitan, öppna Terminal, kör följande kommando och starta om Mac.

sudo / usr / libexec / xpccachectl

Efter att ha gjort det, bygg och kör din förlängning genom att välja lämpligt schema. När det frågar vilken app som ska köras, leta efter Xcode och se till att du väljer beta version av Xcode 8. En ny Xcode-version kommer att lanseras med applikationsikonen gråtonad så att du kan känna igen i vilket fall Xcode du testar tillägget.

I det nya Xcode-exemplet skapar du ett nytt projekt eller öppnar en befintlig och går till Redaktör> Ren stängning> Källeditorns kommando. Se till att ha minst en tillslutning i den aktuella fokuserade Swift-filen för att se resultatet. Som du kan se i följande animering fungerar vår tillägg.

Källeditorns kommando är standardnamnet för ett kommando. Du kan ändra det i Info.plist fil av förlängningen. Öppna den och ändra strängen till Ren syntax.

Vi kan också tilldela en genväg för att automatiskt anropa Ren syntax kommando. Öppna Xcode s Inställningar och välj Nyckelbindningar flik. Söka efter Ren syntax och kommandot kommer att visas. Klicka till höger om det och tryck på genvägen du vill använda, till exempel, Kommando-Alt-Shift-+. Du kan nu gå tillbaka till källfilen och trycka på den genvägen för att påbörja den direkt.

7. Tips och tricks

Xcode 8 och källredigeringstillägg är fortfarande i beta vid skrivningstillfället. Följande tips kan hjälpa dig att felsöka några problem som du kanske stöter på.

Om din anknytning inte kan väljas i Xcode-testaxemplet, dödar du com.apple.dt.Xcode.AttachToXPCService bearbeta och kör förlängningen igen.

Byt bara tillbaka de linjer som du ändrar i bufferten. Detta gör förlängningen köra snabbare och det kommer att ha mindre chanser att bli dödade av Xcode. Det senare kan hända om Xcode tror att ett kommando på din förlängning tar för lång tid.

Om du vill visa flera kommandon, tilldela varje kommando en annan identifierare och använd commandIdentifier egendom på XCSourceEditorCommandInvocation objekt att erkänna vilken användare användaren utlöst.

Slutsats

Att skapa Xcode Source Editor är mycket enkelt. Om du kan förbättra ditt arbetsflöde och påskynda din utveckling genom att skapa en källredigeringsutvidgning, fortsätt och gör det hänt. Apple introducerade ett nytt sätt för utvecklare att dela signerade plugins via Mac App Store så att du kan släppa ditt arbete och se till att andra utvecklare dra nytta av det.

Du kan hitta källkoden för exemplet på denna handledning på GitHub.