Stacktrace

Sida 1/23:123451020...23

Under några månaders tid har jag stört mig på att Ubuntu återställer tangentbindningar som jag gjort när datorn bootas om. T.ex. så krockar Ubuntus Alt+F7 Move Window med Intellijs IDEAs find. Det verkar vara en bug i 12.10 och 13.04 som introducerade detta.

Som temporär lösning på problemet har jag lagt följande i filen $HOME/.gsettings som jag sedan läser in i $HOME/.bashrc (tidigare skrev jag att man kunde lägga inläsningen i .profile istället, men det verkar som att Ubuntu återställer gsettings efter att .profile körts).

# Check what bindings are available
# gsettings list-recursively  |grep key|less

gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-left "['<Shift><Control><Alt>Left']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-right "['<Shift><Control><Alt>Right']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-up "['<Shift><Control><Alt>Up']"
gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-down "['<Shift><Control><Alt>Down']"

gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-left "['<Control><Super><Alt>Left']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-right "['<Control><Super><Alt>Right']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-up "['<Control><Super><Alt>Up']"
gsettings set org.gnome.desktop.wm.keybindings switch-to-workspace-down "['<Control><Super><Alt>Down']"

gsettings set org.gnome.settings-daemon.plugins.media-keys screensaver '<Super>l'
gsettings set org.gnome.desktop.wm.keybindings begin-move "['<Super>F7']"
gsettings set org.gnome.desktop.wm.keybindings begin-resize "['<Super>F8']"
gsettings set org.gnome.desktop.wm.keybindings show-desktop "['<Super>d']"

gsettings set org.gnome.desktop.wm.keybindings toggle-shaded "['disabled']"
if [ -f "$HOME/.gsettings" ]; then
	. "$HOME/.gsettings"
fi

Som nyexad webbprogrammerare var det inte helt lätt att slänga sig in i certifieringsdjungeln. Det var många nya begrepp och ofta förstod jag varken frågorna eller förklaringarna när jag först började läsa. Även om jag hade haft Java som huvudspråk under min utbildningen var jag inte så van vid att prata om språket och jag hade definitivt inte ställts inför frågor om regler på hur saker och ting fungerar beroende på om man gör si eller så. Vissa klasser och metoder hade jag inte stött på tidigare och då blev de kodexempel, som egentligen skulle underlätta, ett hinder mer än ett hjälpmedel. Men skam den som ger sig… nu har jag min Java Programmer-certifiering. Det här är mina tips för hur du lyckas! Läs mer >>

Vagrant är ett verktyg för att på ett smidigt sätt via kommandoraden kunna hantera olika virtuella boxar (Oracle VirtualBox). Vagrant används för att skapa och konfigurera lättviktiga, reproducerbara och portabla utvecklingsmiljöer.

Grundkrav

Sätt igång

Då är vi redo att börja. För att skapa en ny virtuell box med Ubuntu 12.04 LTS kör du bara följande kommandon:

$ vagrant box add precise64 http://files.vagrantup.com/precise64.box
$ mkdir -p testenv
$ cd testenv
$ vagrant init precise64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

Kommandot på rad 1 laddar ned en färdig box med Ubuntu 12.04 LTS. Denna box namnges till precise64 och kan sedan återanvändas för flera virtuella maskiner. Nedladdning sker endast en gång. Rad 2 och 3 skapar en katalog där din virtuella maskin sparas. Kommandot på rad 4 skapar en så kallad Vagrantfile som beskriver hur just din box ska konfigureras (bland annat port forwarding). Vagrant själva skriver att:

A Vagrantfile is to Vagrant as a Makefile is to Make

Innehållet i vår nyskapade Vagrantfile ser ut ungefär så här:

Vagrant::Config.run do |config|
  # Setup the box
  config.vm.box = "precise64"
end

Den katalogen som innehåller Vagrantfile mappas (per default) upp som en shared folder så din maskin och den virtuella boxen kan dela filer där på ett smidigt sätt.

För att sedan starta vår virtuella server används följande kommando:

$ vagrant up

Och för att koppla upp dig via SSH mot servern körs detta kommando:

$ vagrant ssh

När du kopplat upp dig via SSH kan du accessa dina delade filer i foldern /vagrant

Om du gör förändringar av din virtuella box som du sedan vill återanvända kan du skapa egna paket (boxar) som du senare kan utgå från. Detta sker enkelt via kommandot:

$ vagrant package

Då skapas en box – package.box – som kan läggas till bland dina befintliga boxar med hjälp av

$ vagrant box add my_box /path/to/package.box

När du känner att du är färdig med din virtuella box kan du använda följande kommando för att stänga ned maskinen (och därmed spara CPU/RAM):

$ vagrant halt

Alternativt, om du bara vill göra en suspend (det går snabbare att starta maskinen senare isf):

$ vagrant suspend

För att starta maskinen efter halt eller suspend är det bara att köra:

$ vagrant up

Om du vill ta bort din virtuella box från disken helt och hållet kör du bara kommandot:

$ vagrant destroy

Vagrant erbjuder också stöd för mer avancerade features såsom provisioning mha Chef eller Puppet. Allt detta finns att läsa på Vagrants hemsida.

Så, superenkel hantering av virtuella boxar med hjälp av Vagrant – rekommenderas varmt!

Lathund:

$ vagrant init Skapar en Vagrantfile
$ vagrant up Startar en virtuell box
$ vagrant halt Stoppar den virtuella boxen
$ vagrant suspend Pausar den virtuella boxen
$ vagrant destroy Stoppar och tar bort den virtuella boxen från disken
$ vagrant package Skapar ett nytt box-paket baserat på en befintlig box
$ vagrant box add my_box /path/to/package.box Lägger till en ny box-typ (my_box) som pekas ut via path eller HTTP
$ vagrant box list Listar tillgängliga boxar för din lokala miljö. En lista över boxar nedladdningsbara boxar finns här.

I den här artikeln ska jag skriva lite om EclEmma, en plugin till Eclipse för testramverket EMMA. Pluginen är inte på något sätt ny, men inte desto mindre användbar. Verktyget är till för att visa dig hur väl dina tester täcker din kod, s. k. test coverage.

Även om man utvecklar enligt TDD (Test Driven Development) så kan det vara bra att få ett kvitto på att ens egen bild av testerna stämmer överens med verkligheten. För den som inte utvecklar testdrivet är EMMA en riktig ”eye-opener” för att, allt som oftast, inse att det behövs fler tester.

Jag fortsätter med ett exempel av Hello World-kaliber. Ladda gärna hem pluginen själv och prova samtidigt, projektets hemsida är www.eclemma.org där du kan välja manuell nerladdning eller använda länken till projektets update-site, samt att det finns tillgängligt i Eclipse Marketplace.

Då kör vi. Testet ser ut såhär:

public class EmmaTest {

 @Test
 public void testGreeter() {
    Greeter greeter = new Greeter();
    Assert.assertEquals("Hello Cygni!", greeter.greet("Cygni"));
 }
}

Och klassen vi ska testa:

public class Greeter {

 public String greet(String name) {
    if(name != null) {
       return "Hello " + name + "!";
    } else {
       return "Who are you?";
    }
 }

 public String greetSimple() {
    return "Hello you!";
 }
}

Att testet inte täcker hela Greeter-klassen har du nog redan insett. Vi låter dock EclEmma sköta analysen.

När EclEmma är installerat dyker ytterligare ett alternativ för att exekvera upp. Sedan tidigare har vi Run as och Debug as, men nu kommer även Coverage as att finnas tillgängligt. Om du kör Java-perspektivet skall också en ikon för detta ha tillkommit (kör du andra perspektiv kan du behöva lägga till ikonen via ”Customize perspective”). Vi kör testet via Coverage as:

Testet körs och vi får upp Coverage-vyn, samt att kodraderna i de klasser där det körts kod kommer att ha fått lite färg. Vi börjar med Coverage-vyn:

Som synes kan vi gå ner på olika nivåer för att tydligare se var det täcker bättre eller sämre. Efter att ha expanderat trädet fullt ut ner på metodnivå ser vi att greetSimple() har 0% täckning och att greet() behöver testas mer för att nå 100%. Metoden greetSimple() tog jag bara med här för att visa på hur användbart det är att kunna se test coverage på metodnivå och på så sätt tydligare identifiera svagheter, men jag låter den vara otestad för det här exemplet.

Om vi öppnar klassen Greeter, så ser ni tydligt vad som är testat och inte:

I greetSimple() är det inte så mycket att tala om, den är röd (no coverage) eftersom vi inte har något test som kör metoden. I greet() är raden med ”Who are you?” röd eftersom vi inte har gjort något anrop där if-satsen utvärderas till false.

Den gröna raden är grön (full coverage) därför att det är den rad som exekverades när metoden returnerade ”Hello Cygni!”, det väntade resultatet av vårt test.

Den gula raden betyder att raden är delvis täckt (partial coverage), en mycket användbar indikator. I det här fallet vet vi att det finns två scenarion för if-satsen. Antingen har argumentet name värdet null, eller så är name skilt från null. I vårt test skickade vi in ”Cygni”, name var alltså skilt från null. EclEmma talar också om för oss hur många fall vi har missat om vi håller muspekaren över diamantikonen bredvid:

Vi skriver ytterligare ett test för att nå 100% test coverage i metoden greet():

@Test
 public void testGreeterNullArg() {
    Greeter greeter = new Greeter();
    Assert.assertEquals("Who are you?", greeter.greet(null));
 }

Resultatet ser nu mycket trevligare ut:

En inställning som är bra att känna till är vilken typ av counter man kör. Hur stor test coverage dina tester har kan variera stort beroende på hur man räknar. I vårt exempel kunde vi se att vi i if-satsen hade två stycken branches. I första testet kördes bara ett anrop där uttrycket i if-satsen var sant (name var skilt från null), vilket innebar att vi täckte en branch av två – branchen där name var null kördes inte. Alltså hade vi i det testet 50% branch coverage på den raden.

Men, om vi istället räknar line coverage, så är siffran 100% eftersom line coverage inte tar hänsyn till vilken typ av kodrad som exekveras, bara att den exekveras. Klicka på den vita nedåtriktade pilen i coverage-vyn för att ändra typ av counter:

Du kan läsa mer om de olika typerna av counters som finns på EclEmma‘s hemsida eller exempelvis Wikipedia.

Två tips innan vi är färdiga:

  1. EMMA och andra liknande verktyg (Cobertura till exempel) finns som plugins till exempelvis Maven och Jenkins, som då genererar en rapport över hur testerna gick i ett bygge. Att ha statistik och rapporter över testresultat och trender i projektet ger en trevlig överblick.
  2. Om du kör ett mörkt tema för Eclipse, vilket inte är särskilt ovanligt, rekommenderar jag att ändra highlight-färgerna för EclEmma, annars är risken stor att du inte ser texten på raderna. Gå till Window -> Preferences -> General -> Editors -> Text Editors -> Annotations och välj mörkare färger för alternativen Full coverage, Partial coverage och No coverage.

Dropwizard är en körmiljö och ett ramverk för att enkelt utveckla små enheter i form av RESTful webtjänster. En stack bestående av bl.a Jetty, Jersey, Jackson, slf4j, JDBI och en föreslagen projektstruktur gör det väldigt lätt att komma igång!

Begrepp

Dropwizard har idenitifierat följande aktörer och entiteter i sin stack:

Configuration

Konfigurationen är till för att hålla miljöspecifika aspekter av tjänsten. Det kan t.ex vara databaskonfiguration eller nödvändiga sökvägar och url:ar. Konfigurationen skrivs i formatet YAML. Genom JSON-annotationer i din klass läser DropWizard automatiskt upp konfigurationen och populerar din konfigurationsklass.

Representation

Detta är de objekt som ska skickas mellan klient och server och är i sin enklaste form vanliga POJOs. Jackson används för serialisering och deserialisering. DropWizard rekommenderar att dessa objekt är immutable.

Resource

Det är resurserna som exponerar REST API:et. Varje resurs och metod har en URI och klassen annoteras med javax.ws.rs.*-typerna för att definiera sökvägar, innehållstyper och metod. DropWizard använder Jersey-implementationen.

Health check

Hälsokontroller är små kodsnuttar som testar att tjänsten är uppe och att allt är som det ska. Status för hälsokontrollerna kan inspekteras via en speciell admin-url. DropWizard skapar automatiskt några hälsokontroller, bl.a en som kontrollerar att databasanslutningen är korrekt (om man har en i sitt projekt).

Service

Servicen ansvarar för att dra igång tjänsten med en konfiguration och med resurserna initialiserade med eventuella beroenden. Detta sker genom en vanlig main-metod(public static void main(String[] args) { ... } ).

I vårt exempelprojekt ser serviceklassen ut så här:

public class MainService extends Service<MainConfiguration> {
    public static void main(String[] args) throws Exception {
        new MainService().run(args);
    }

    @Override
    public void initialize(Bootstrap<MainConfiguration> mainConfigurationBootstrap) {
        mainConfigurationBootstrap.addBundle(new AssetsBundle("/assets/", "/"));
    }

    @Override
    public void run(MainConfiguration config, Environment environment) throws Exception {

        DBI dbi = initDatabaseConnection(config, environment);

        final EventsRepository eventsRepository = dbi.onDemand(EventsRepository.class);
        final ExpensesRepository expensesRepository = dbi.onDemand(ExpensesRepository.class);

        environment.addResource(new EventsResource(eventsRepository));
        environment.addResource(new ExpensesResource(expensesRepository));
    }

    private DBI initDatabaseConnection(MainConfiguration config, Environment environment) throws ClassNotFoundException {

        final DBIFactory factory = new DBIFactory();
        final DBI jdbi = factory.build(environment, config.getDatabaseConfiguration(), "db");

        createTables(jdbi);

        return jdbi;
    }

    private void createTables(DBI dbi) {

        Handle handle = dbi.open();

        handle.execute(EventsRepository.CREATE_TABLE_STATEMENT);

        handle.execute(ExpensesRepository.CREATE_TABLE_STATEMENT);

        handle.close();
    }
}

För dig som är van vid Spring eller något annat DI-ramverk kan det kännas lite konstigt att själv behöva instansiera t.ex resursklasserna (och skjuta in Repository-implementationerna). Eftersom tanken med en DropWizard tjänst är att ansvara för en relativt liten delmängd av ett system så tycker jag inte att detta är särskilt besvärande.

Resurser, dvs REST-tjänsterna, aktiveras genom att lägga till dem till instansen av Environment. Se rad 19-20 ovan.

Komma igång

Checka ut exempelprojektet och bygg:

git clone git://github.com/cygni-stacktrace/dropwizard-sample.git
cd dropwizard-sample
mvn package

Starta tjänsten med kommandot server och filnamnet för konfigurationen:

java -jar target/expenses-1.0-SNAPSHOT.jar server development.yml

Rest-API:et ligger under kontextet /api, en GET-operation för att lista events finns t.ex här: http://localhost:8080/api/event

Admingränssnittet med länk till Health check finns här: http://localhost:8081

Testning

Testning av resurser är en enkel historia med DropWizard. Genom att låta din testklass uttöka ResourceTest kan du lägga till resursen under test så här:

    @Override
    protected void setUpResources() throws Exception {
        eventsRepository = mock(EventsRepository.class);
        addResource(new EventsResource(eventsRepository));
    }

En testmetod:

    @Test
    public void shouldShowOneEvent() throws IOException {
        //given
        Event event = new Event(1, "An event", null);

        given(eventsRepository.findById(event.getId())).willReturn(event);

        //when
        Event result = client().resource("/event/1").get(Event.class);

        //then
        assertThat("event should be returned", result, is(event));
    }

Dropwizard drar igång Jersey och invokerar anropen i testet via en HTTP-klient så hela request/response kedjan går över JSON och HTTP. Detta är bra för då testas även att Jackson kan serialisera och deserialisera dina POJO:s.

Databasstöd

Dropwizard har moduler med stöd för Hibernate och JDBI. I exempelprojektet används JDBI.

Slutsats

Det är väldigt lätt att komma igång med Dropwizard och jag tycker att de valt en vettig stack med hjälpbibliotek. Den föreslagna projektstrukturen och användandet av Maven gör att det fungerar bra i alla stora IDE:er. Att inkludera Health checks direkt från början känns väldigt bra och det är befriande att ha en app som kan köras helt stand-alone (d.v.s den behöver inte deployas i en webcontainer). Jag tycker också att de tänkt till bra kring testningen.

Om man planerar att börja använda Dropwizard i ett större sammanhang behövs dock en strategi för hur tjänster ska kunna versionshanteras samt upptäckas.

Vidare läsning

http://dropwizard.codahale.com

Detta inlägg argumenterar för att mönstret

try {
   ...
} catch(SomeCheckedException e) {
   e.printStackTrace();
}

är ett anti-pattern och definitivt ej bör rekommenderas som ett generellt felhanteringsmönster.

Vad är det då för fel på denna konstruktion? Jo, problemet är att den bryter mot en bra grundprincip inom felhantering, ”fail fast”.

Principen ”fail fast” bygger på att man avbryter programmet så fort ett fel uppstår. Huvudorsaken till att avbryta tidigt är att undvika följdfel. Samtidigt så undviks maskeringar av fel, vilket gör det lättare att diagnostisera och korrigera brister. Följs denna teknik och kombineras med vältäckande tester kan man eliminera många buggar och uppnå en hög genomgående kvalité i sin produkt.

När denna princip är på plats kan man sedan välja göra programmet mer flexibelt genom att selektivt lägga till felhanteringsstrategier.

Detta görs ofta genom att lägga till alternativa strategier för specifika felfall. Detta benämns ofta som ”graceful degradation”. Som ett exempel kan man tänka sig en e-handel som köar upp ordrar då kontakten med banken faller bort. Har man en sådan ”plan b” så har man täckt upp för det specifika felfallet att kontakten med banken faller bort. Ett annat exempel är att falla tillbaka till en enklare webbsida då en plug-in saknas eller en äldre browser används.

För oplanerade fel, sådana där man ofta inte har någon uttänkt strategi, är det bästa man kan göra att återställa systemet till ett känt säkert läge. Ett allmängiltigt sätt att skicka ett program till ett känt läge är att avbryta det. Är ditt system inte livsuppehållande eller på annat sätt kritiskt är detta läge även säkert. Så en bra grundstrategi är att avbryta programmet när ett okänt fel uppstår.

Tillbaka då till strategin att anropa printStackTrace(). Denna felhanterare gör två saker:

  1. Skriver ut en felrapport
  2. Fortsätter exekveringen av programmet

Det är i huvudsak punkt två som bryter mot ”fail fast”. Om man har en ”graceful degradation” eller ”fail safe”-strategi på plats så bör man när man fångat felet anropa ”plan b”, inte bara fortsätta. Är felet istället oplanerat så bör man så snart som möjligt försätta programmet i ett säkert läge och skriva ut en felrapport.

I printStackTrace-fallet försätts inte programmet i ett säkert läge. Programmet tillåts fortsätta att exekvera och kommer förmodligen trigga följdfel. I avseendet följdfel är därmed denna form av felhantering inte bättre än det välkända anti-patternet att svälja felet helt:

try {
   ...
} catch(SomeCheckedException e) {
  //dålig taktik
  //no-op
}

. Inte heller taktiken att skriva ut felrapporten på en logg undslipper detta argument:

try {
   ...
} catch(SomeCheckedException e) {
   //dålig taktik
  logger.error(e);
}

. En tredje teknik som förekommer är log and throw:

try {
   ...
} catch(SomeCheckedException e) {
   //dålig taktik
  logger.error(e);
  throw new RuntimeException(e);
}

. Att kasta vidare räcker gott och väl, annars riskerar man flera utskrifter för samma fel.

Man vill alltså försätta programmet i ett säkert läge. Dessutom vill man ha en felutskrift utan duplikat. Vän av ordning frågar sig såklart hur man åstadkommer detta på ett enkelt sätt. Svaret är enkelt: kasta exceptionet vidare:

try {
   ...
} catch(SomeCheckedException e) {
   //bra taktik
  throw new RuntimeException(e);
}

.
Vad åstadkommer en sådan konstruktion? Jo, felet kommer att propageras uppåt i stacken tills det når trådens topp, där ett stacktrace skrivs ut innan tråden avslutas. Detta beteende är inbyggt i Java. Har du en enkel applikation med endast en non-deamon-tråd så kommer programmet även att avslutas i samband med att ditt fel skrivs ut. Fallet multitrådade program är mer invecklat och tas inte upp i detta inlägg.

För att på ett enkelt sätt kunna följa dessa principer rekommenderar jag att du ändrar mallen för ”surround with try-catch” i ditt IDE så att den kastar checked exceptions vidare, istället för att anropa printStackTrace().

I Eclipse kan du göra detta i inställningen Java > Code Style > Code Templates och ändra från default

// ${todo} Auto-generated catch block
${exception_var}.printStackTrace();

till

throw new RuntimeException(${exception_var});

På detta sätt får du den bra taktiken per default när du gör ”quick fix”!

quick fix

Detta är den sista delen av tre i en artikelserie om automatiserade integrationstester. Den första delen ger en kort beskrivning av syftet med integrationstester och de utmaningar som ofta uppstår vid testning. Där visar jag också hur man kan parallellisera tester i JUnit för att minska exekveringstiden.

Del två visar på användningen av parametriserade tester och hur man på ett bra sätt kan använda extern testdata (testfixtures).

Denna sista del visar hur man kan koppla ihop sina testsviter med open source-verktyget TestLink för att få fram trevliga rapporter. Läs mer >>

Detta är den andra delen av tre i en artikelserie om automatiserade integrationstester. Den första delen ger en kort beskrivning av syftet med integrationstester och de utmaningar som ofta uppstår vid testning. Där visar jag också hur man kan parallellisera tester i JUnit för att minska exekveringstiden.

Denna del visar på användningen av parametriserade tester och hur man på ett bra sätt kan använda extern testdata (testfixtures).

Den sista delen visar hur man kan koppla ihop sina testsviter med open source-verktyget TestLink för att få fram trevliga rapporter. Läs mer >>

När man skall skriva automatiserade integrations- eller regressionstester ställs man delvis inför lite andra utmaningar än vad som gäller för ”vanliga” enhetstester. Detta är den första delen av tre i en artikelserie om automatiserade integrationstester. Denna första del ger en kort beskrivning av syftet med integrationstester och de utmaningar som ofta uppstår vid testning. Där visar jag också hur man kan parallellisera tester i JUnit för att minska exekveringstiden.

Del två visar på användningen av parametriserade tester och hur man på ett bra sätt kan använda extern testdata (testfixtures).

Den sista delen visar hur man kan koppla ihop sina testsviter med open source-verktyget TestLink för att få fram trevliga rapporter.

Läs mer >>

iTerm2 är en mycket kompetent terminal för Mac OS X. Man kan t.ex. öppna nya terminaler i form av flikar eller splittade fönster. Navigering mellan tabbar sker med Cmd-<n> där n är ordningsnumret på fliken, eller Cmd-Shift-Höger/Vänster. För att hoppa mellan splittade fönster använder man Cmd-Alt-Höger/Vänster.

Om du vill lägga till egna bindningar är detta också möjligt. Under Preferences/Keyboard kan du binda tangenter till ett 20-tal olika iTerm-funktioner.

Det är också möjligt att binda till bash-funktioner. Om du vill binda en sekvens som inte innehåller Cmd, gör du allt i .inputrc och blandar inte in iTerm överhuvudtaget.

$ cat .inputrc
"\e\e[C": forward-word
"\e\e[D": backward-word

Ovanstående binder Alt-Höger till forward-word och Alt-Vänster till backward-word. Skriv man bash och sök på dessa funktionsnamn för att få fler uppslag på vad man kan göra. Passa också på att läsa avsnittet om readline för att förstå notationen i .inputrc. Med hjälp av read (eller cat) följt av return kan du se vilka styrkoder olika tangenter ger.

$ read
^[^[[D
$ read
^[^[[C

Ovan har jag tryckt på Alt-Vänster resp Alt-Höger. Tecknet ^[ står för Escape eller ASCII 27. Se nedan för en förteckning över olika tecken/koder.

Om du vill binda en bash-funktion till en sekvens med Cmd, måste du använda dig av iTerms ”Send Escape Sequence” eller ”Send Hex Codes” under Preferences/Keyboard. T.ex. för att binda Cmd-vänster till Fn-Vänster som är Home på min laptop väljer man ”Send Escape Sequence” ^[[H, det inledande Escape-tecknet ^[ ges av iTerm.

När du nu trycker på Cmd-Vänster skickar iTerm ^[[H vidare till Bash vilket råkar ha detta mappat till beginning-of-line. Kör bind -p för att lista alla funktioner och dess nuvarande bindningar. På min maskin kan man se att Ctrl-A även är mappad till nyss nämnda funktion. Vi skulle därför ha kunnat skicka ett denna sekvens från iTerm, men då måste vi använda oss av ”Send Hex Code” istället. Hex-koden för Ctrl-A är 01.

Vissa sekvenser som innehåller Ctrl eller osynliga tecken som TAB och RET kan man behöva gå in i verbatim-läge (Ctrl-V) för att skriva ut. Nedan har jag trycket Ctrl-V följt av TAB och ser då att det är ^I eller ASCII 09. Vidare ser vi att Ctrl-V följt av Ctrl– ger ^_ eller ASCII 1F.

$ read
^I
$ read
^_

Default-bindningen i bash är att undo är bundet till Ctrl– (minus). Alltså kan du binda t.ex. Cmd-Z i iTerm till Bash-undo genom att skicka Hex-koden 1F.

Sida 1/23:123451020...23