[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"projectName\": \"oh-my-posh\",\n  \"projectOwner\": \"JanDeDobbeleer\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"files\": [\n    \"website/docs/contributors.md\"\n  ],\n  \"imageSize\": 100,\n  \"commit\": true,\n  \"commitConvention\": \"angular\",\n  \"contributors\": [\n    {\n      \"login\": \"lnu\",\n      \"name\": \"Laurent Nullens\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1829553?v=4\",\n      \"profile\": \"https://github.com/lnu\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"TravisTX\",\n      \"name\": \"Travis Collins\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/934490?v=4\",\n      \"profile\": \"https://github.com/TravisTX\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jos3s\",\n      \"name\": \"José Ulisses\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/50359547?v=4\",\n      \"profile\": \"https://github.com/jos3s\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"nwykes\",\n      \"name\": \"Nathan Wykes\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/593993?v=4\",\n      \"profile\": \"https://github.com/nwykes\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"tillig\",\n      \"name\": \"Travis Illig\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1156571?v=4\",\n      \"profile\": \"http://www.paraesthesia.com/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"evilz\",\n      \"name\": \"Vincent B.\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2937862?v=4\",\n      \"profile\": \"http://www.evilznet.com/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"erclu\",\n      \"name\": \"Luca Ercole\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/30255227?v=4\",\n      \"profile\": \"https://erclu.github.io/cv/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"LarsBauer\",\n      \"name\": \"Lars Bauer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3920045?v=4\",\n      \"profile\": \"https://larsbauer.xyz/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"RobCannon\",\n      \"name\": \"Rob Cannon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/189862?v=4\",\n      \"profile\": \"https://github.com/RobCannon\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Vixb1122\",\n      \"name\": \"Vixb\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17810492?v=4\",\n      \"profile\": \"https://github.com/Vixb1122\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"zeyugao\",\n      \"name\": \"Elsa Granger\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6374697?v=4\",\n      \"profile\": \"https://github.com/zeyugao\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"softweaprograma\",\n      \"name\": \"Anthony G\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35231092?v=4\",\n      \"profile\": \"https://github.com/softweaprograma\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"gitolicious\",\n      \"name\": \"gitolicious\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/26963495?v=4\",\n      \"profile\": \"https://github.com/gitolicious\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"irdkwmnsb\",\n      \"name\": \"Maxim\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/8657078?v=4\",\n      \"profile\": \"https://alzhanov.ru/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"PIYUSH194\",\n      \"name\": \"PIYUSH194\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2896456?v=4\",\n      \"profile\": \"https://github.com/PIYUSH194\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"97krihop\",\n      \"name\": \"97krihop\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/24739853?v=4\",\n      \"profile\": \"https://github.com/97krihop\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"stefanes\",\n      \"name\": \"Stefan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5484354?v=4\",\n      \"profile\": \"https://github.com/stefanes\",\n      \"contributions\": [\n        \"design\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"moritz-meier\",\n      \"name\": \"Moritz Meier\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/60762067?v=4\",\n      \"profile\": \"https://github.com/moritz-meier\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jetersen\",\n      \"name\": \"Joseph Petersen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1661688?v=4\",\n      \"profile\": \"https://github.com/jetersen\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Goliaita\",\n      \"name\": \"Davide Basile\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11245411?v=4\",\n      \"profile\": \"https://github.com/Goliaita\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"sukso96100\",\n      \"name\": \"Youngbin Han\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1916739?v=4\",\n      \"profile\": \"http://youngbin.xyz/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"mateusnssn\",\n      \"name\": \"Mateus Nunes\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/69170710?v=4\",\n      \"profile\": \"https://mateusnssp.github.io/mateusnssp/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"PixelRobots\",\n      \"name\": \"PixelRobots\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22979170?v=4\",\n      \"profile\": \"https://pixelrobots.co.uk/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"RishabhSood\",\n      \"name\": \"RishabhSood\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/55499929?v=4\",\n      \"profile\": \"https://github.com/RishabhSood\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"SagarYadav17\",\n      \"name\": \"Sagar Yadav\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/47110215?v=4\",\n      \"profile\": \"https://github.com/SagarYadav17\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"WolfspiritM\",\n      \"name\": \"Adrian\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5904171?v=4\",\n      \"profile\": \"https://github.com/WolfspiritM\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"MJECloud\",\n      \"name\": \"Maurice\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22131101?v=4\",\n      \"profile\": \"https://github.com/MJECloud\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"samuelfahrngruber\",\n      \"name\": \"samuelfahrngruber\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35682879?v=4\",\n      \"profile\": \"https://github.com/samuelfahrngruber\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"zilmarr\",\n      \"name\": \"Zilmar de Souza Junior\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5557367?v=4\",\n      \"profile\": \"https://github.com/zilmarr\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"AsafMah\",\n      \"name\": \"AsafMah\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6424271?v=4\",\n      \"profile\": \"https://github.com/AsafMah\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"cinnamon-msft\",\n      \"name\": \"Kayla Cinnamon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/48369326?v=4\",\n      \"profile\": \"https://github.com/cinnamon-msft\",\n      \"contributions\": [\n        \"design\",\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"cbargren\",\n      \"name\": \"Chris Bargren\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1050712?v=4\",\n      \"profile\": \"https://github.com/cbargren\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"tonybaloney\",\n      \"name\": \"Anthony Shaw\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1532417?v=4\",\n      \"profile\": \"https://tonybaloney.github.io/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"mifieldxu\",\n      \"name\": \"Mifield\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5520179?v=4\",\n      \"profile\": \"https://github.com/mifieldxu\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"benallred\",\n      \"name\": \"Ben Allred\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3902274?v=4\",\n      \"profile\": \"https://github.com/benallred\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"riazXrazor\",\n      \"name\": \"Riaz Laskar\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13194363?v=4\",\n      \"profile\": \"https://riazxrazor.herokuapp.com/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Don-Vito\",\n      \"name\": \"Don-Vito\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4639110?v=4\",\n      \"profile\": \"https://github.com/Don-Vito\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"FabianEscarate\",\n      \"name\": \"Fabian Roberto Escarate\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19978896?v=4\",\n      \"profile\": \"https://github.com/FabianEscarate\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"xt0rted\",\n      \"name\": \"Brian Surowiec\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/831974?v=4\",\n      \"profile\": \"https://github.com/xt0rted\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"ojullien\",\n      \"name\": \"Olivier Jullien\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3778194?v=4\",\n      \"profile\": \"https://twitter.com/OJullien\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"cdonnellytx\",\n      \"name\": \"Chris Donnelly\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/183046?v=4\",\n      \"profile\": \"https://github.com/cdonnellytx\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"KyleCrowley\",\n      \"name\": \"Kyle Crowley\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6757487?v=4\",\n      \"profile\": \"https://github.com/KyleCrowley\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"gitolicious\",\n      \"name\": \"gitolicious\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/26963495?v=4\",\n      \"profile\": \"https://github.com/gitolicious\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jeroen7s\",\n      \"name\": \"Jeroen Evens\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10954827?v=4\",\n      \"profile\": \"https://github.com/jeroen7s\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"equinox\",\n      \"name\": \"equinox\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6139999?v=4\",\n      \"profile\": \"https://github.com/equinox\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"DamianoPellegrini\",\n      \"name\": \"Damiano Pellegrini\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/41305552?v=4\",\n      \"profile\": \"https://github.com/DamianoPellegrini\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"timon-schelling\",\n      \"name\": \"Timon Schelling\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36821505?v=4\",\n      \"profile\": \"https://timokrates.de/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"zeyugao\",\n      \"name\": \"Elsa Granger\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6374697?v=4\",\n      \"profile\": \"https://github.com/zeyugao\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"Daksh777\",\n      \"name\": \"Daksh P. Jain\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43648146?v=4\",\n      \"profile\": \"https://daksh.eu.org/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"boarder2\",\n      \"name\": \"Willie Zutz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19351?v=4\",\n      \"profile\": \"http://bit-shift.com/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"uruz-7\",\n      \"name\": \"uruz-7\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/15071454?v=4\",\n      \"profile\": \"https://github.com/uruz-7\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"beppler\",\n      \"name\": \"Carlos Alberto Costa Beppler\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/66092?v=4\",\n      \"profile\": \"https://github.com/beppler\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"sky96111\",\n      \"name\": \"sky96111\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22412214?v=4\",\n      \"profile\": \"https://github.com/sky96111\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"jantielens\",\n      \"name\": \"Jan Tielens\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9884103?v=4\",\n      \"profile\": \"http://j.tlns.be/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"shedric1\",\n      \"name\": \"shedric1\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/56672838?v=4\",\n      \"profile\": \"https://github.com/shedric1\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"sectorogo\",\n      \"name\": \"sectorogo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/32959212?v=4\",\n      \"profile\": \"https://github.com/sectorogo\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"phil-scott-78\",\n      \"name\": \"Phil Scott\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2447331?v=4\",\n      \"profile\": \"https://github.com/phil-scott-78\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"suuus\",\n      \"name\": \"Suus\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40822355?v=4\",\n      \"profile\": \"https://suuu.us/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"wopian\",\n      \"name\": \"James Harris\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3440094?v=4\",\n      \"profile\": \"https://wopian.me/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"mdlopresti\",\n      \"name\": \"Michael LoPresti\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1293090?v=4\",\n      \"profile\": \"https://github.com/mdlopresti\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"floh96\",\n      \"name\": \"Florian Heberl\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/49693964?v=4\",\n      \"profile\": \"https://github.com/floh96\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"relativityhd\",\n      \"name\": \"Tobias Hölzer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/37540371?v=4\",\n      \"profile\": \"http://tobiashoelzer.dynu.net\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"h4iku\",\n      \"name\": \"Reza Gharibi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3812788?v=4\",\n      \"profile\": \"https://h4iku.github.io\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"JustinGrote\",\n      \"name\": \"Justin Grote\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/15258962?v=4\",\n      \"profile\": \"https://justingrote.github.io\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"henry-js\",\n      \"name\": \"James\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/79054685?v=4\",\n      \"profile\": \"https://github.com/henry-js\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"iarejenius\",\n      \"name\": \"Timothy Wittig\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1031515?v=4\",\n      \"profile\": \"https://wittig.dev\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Descalon\",\n      \"name\": \"Nico Glas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1098500?v=4\",\n      \"profile\": \"https://github.com/Descalon\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"hanskokx\",\n      \"name\": \"Hans Kokx\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1911919?v=4\",\n      \"profile\": \"https://github.com/hanskokx\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"alchatti\",\n      \"name\": \"Majed Al-Chatti\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9209306?v=4\",\n      \"profile\": \"http://alchatti.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"Jan0660\",\n      \"name\": \"Jan0660\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/58996212?v=4\",\n      \"profile\": \"https://jan0660.dev\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"LuiseFreese\",\n      \"name\": \"Luise Freese\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/49960482?v=4\",\n      \"profile\": \"http://www.m365princess.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"asherber\",\n      \"name\": \"Aaron Sherber\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5248041?v=4\",\n      \"profile\": \"https://github.com/asherber\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"SeanKilleen\",\n      \"name\": \"Sean Killeen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2148318?v=4\",\n      \"profile\": \"http://SeanKilleen.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"NickCraver\",\n      \"name\": \"Nick Craver\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/454813?v=4\",\n      \"profile\": \"https://nickcraver.com\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"justin-vogt\",\n      \"name\": \"Justin Vogt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/84424169?v=4\",\n      \"profile\": \"https://github.com/justin-vogt\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"TheOnlyTails\",\n      \"name\": \"TheOnlyTails\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/65342367?v=4\",\n      \"profile\": \"http://theonlytails.com\",\n      \"contributions\": [\n        \"ideas\"\n      ]\n    },\n    {\n      \"login\": \"bewing\",\n      \"name\": \"bewing\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4759896?v=4\",\n      \"profile\": \"https://github.com/bewing\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"shawnwildermuth\",\n      \"name\": \"Shawn Wildermuth\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/568272?v=4\",\n      \"profile\": \"http://wildermuth.com\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"onpikono\",\n      \"name\": \"Ondrej Pinka\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/25362465?v=4\",\n      \"profile\": \"https://github.com/onpikono\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"kasuken\",\n      \"name\": \"Emanuele Bartolesi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2757486?v=4\",\n      \"profile\": \"https://www.emanuelebartolesi.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"qiansen1386\",\n      \"name\": \"Paris Qian\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1759658?v=4\",\n      \"profile\": \"https://qiansen1386.github.io\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"tjackadams\",\n      \"name\": \"Thomas Adams\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2307314?v=4\",\n      \"profile\": \"https://blog.itadams.co.uk\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"gschizas\",\n      \"name\": \"George Schizas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/598065?v=4\",\n      \"profile\": \"http://www.terrasoft.gr/\",\n      \"contributions\": [\n        \"code\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"denelon\",\n      \"name\": \"denelon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/61799811?v=4\",\n      \"profile\": \"https://github.com/denelon\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"AbdelrahmanHafez\",\n      \"name\": \"Hafez\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19984935?v=4\",\n      \"profile\": \"https://github.com/AbdelrahmanHafez\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"TedCrocker\",\n      \"name\": \"Ted Ballou\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/382001?v=4\",\n      \"profile\": \"https://github.com/TedCrocker\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mikesigs\",\n      \"name\": \"Mike Sigsworth\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/811177?v=4\",\n      \"profile\": \"https://discardchanges.com\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"memcpy-rand-rand-rand\",\n      \"name\": \"Will\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/90210865?v=4\",\n      \"profile\": \"https://github.com/memcpy-rand-rand-rand\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"shanselman\",\n      \"name\": \"Scott Hanselman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2892?v=4\",\n      \"profile\": \"http://www.hanselman.com\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"hgreving\",\n      \"name\": \"Harmjan Greving\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/23560667?v=4\",\n      \"profile\": \"https://github.com/hgreving\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Khaos66\",\n      \"name\": \"Khaos\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4013009?v=4\",\n      \"profile\": \"https://github.com/Khaos66\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mattwojo\",\n      \"name\": \"Matt Wojciakowski\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7566797?v=4\",\n      \"profile\": \"http://mattwojo.github.io/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"TheTaylorLee\",\n      \"name\": \"TheTaylorLee\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/53202926?v=4\",\n      \"profile\": \"https://www.powershellgallery.com/profiles/TaylorLee\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"PapiPeppers\",\n      \"name\": \"Papi Peppers\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/57047860?v=4\",\n      \"profile\": \"https://github.com/PapiPeppers\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"erresen\",\n      \"name\": \"erresen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5566441?v=4\",\n      \"profile\": \"https://erresen.github.io\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"icy-comet\",\n      \"name\": \"Aniket Teredesai\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/50461557?v=4\",\n      \"profile\": \"https://aniketteredesai.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"sdebruyn\",\n      \"name\": \"Sam Debruyn\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/963413?v=4\",\n      \"profile\": \"https://debruyn.dev\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"larserikfinholt\",\n      \"name\": \"Lars Erik Finholt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1328417?v=4\",\n      \"profile\": \"https://github.com/larserikfinholt\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"simorgh1\",\n      \"name\": \"Bahram Maravandi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5792905?v=4\",\n      \"profile\": \"https://github.com/simorgh1\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"calebjenkins\",\n      \"name\": \"Caleb Jenkins\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/211001?v=4\",\n      \"profile\": \"http://developingux.com\",\n      \"contributions\": [\n        \"ideas\"\n      ]\n    },\n    {\n      \"login\": \"FlavienMacquignon\",\n      \"name\": \"FlavienMacquignon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/70152975?v=4\",\n      \"profile\": \"https://github.com/FlavienMacquignon\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Victoria-DR\",\n      \"name\": \"Victoria\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/68347113?v=4\",\n      \"profile\": \"https://github.com/Victoria-DR\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"UlanaXY\",\n      \"name\": \"Mikolaj\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/12629308?v=4\",\n      \"profile\": \"https://github.com/UlanaXY\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"markbullplus\",\n      \"name\": \"markbull\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/88931495?v=4\",\n      \"profile\": \"https://github.com/markbullplus\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"brian6932\",\n      \"name\": \"Brian\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/18603393?v=4\",\n      \"profile\": \"https://github.com/brian6932\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"patHyatt\",\n      \"name\": \"Patrick Hyatt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/296125?v=4\",\n      \"profile\": \"http://www.patrickhyatt.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"hezhizhen\",\n      \"name\": \"Zhizhen He\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7611700?v=4\",\n      \"profile\": \"https://github.com/hezhizhen\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jedwillick\",\n      \"name\": \"Jed Willick\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/85419773?v=4\",\n      \"profile\": \"https://github.com/jedwillick\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"eltociear\",\n      \"name\": \"Ikko Ashimine\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22633385?v=4\",\n      \"profile\": \"https://bandism.net/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"CapularisPerpetua\",\n      \"name\": \"Courtney Caldwell\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/32304933?v=4\",\n      \"profile\": \"https://prokopto.dev/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"rfverbruggen\",\n      \"name\": \"Robbert Verbruggen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2320197?v=4\",\n      \"profile\": \"https://github.com/rfverbruggen\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Merlin2001\",\n      \"name\": \"Marcus Mangelsdorf\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13134791?v=4\",\n      \"profile\": \"https://github.com/Merlin2001\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"andresrinivasan\",\n      \"name\": \"André Srinivasan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/134301?v=4\",\n      \"profile\": \"http://linkedin.com/andresrinivasan\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ehawman-rosenberg\",\n      \"name\": \"ehawman-rosenberg\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/81652082?v=4\",\n      \"profile\": \"https://github.com/ehawman-rosenberg\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"claudiospizzi\",\n      \"name\": \"Claudio Spizzi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1934246?v=4\",\n      \"profile\": \"https://spizzi.net/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"estruyf\",\n      \"name\": \"Elio Struyf\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2900833?v=4\",\n      \"profile\": \"https://www.eliostruyf.com\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"oalders\",\n      \"name\": \"Olaf Alders\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/96205?v=4\",\n      \"profile\": \"https://www.olafalders.com/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"DavidDeSloovere\",\n      \"name\": \"David De Sloovere\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/352626?v=4\",\n      \"profile\": \"https://blog.deltacode.be\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"LensPlaysGames\",\n      \"name\": \"LensPlaysGames\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/69637718?v=4\",\n      \"profile\": \"https://lensor-radii.netlify.app\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"atakiya\",\n      \"name\": \"Alex 'Avunia' Takiya\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6952402?v=4\",\n      \"profile\": \"https://takiya.eu\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"kenmorse\",\n      \"name\": \"kenmorse\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/63734484?v=4\",\n      \"profile\": \"https://github.com/kenmorse\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"xadozuk\",\n      \"name\": \"xadozuk\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/780423?v=4\",\n      \"profile\": \"https://github.com/xadozuk\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"vedantmgoyal9\",\n      \"name\": \"Vedant\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/83997633?v=4\",\n      \"profile\": \"https://bittu.eu.org\",\n      \"contributions\": [\n        \"design\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"lewis-yeung\",\n      \"name\": \"L. Yeung\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/83903009?v=4\",\n      \"profile\": \"https://github.com/lewis-yeung\",\n      \"contributions\": [\n        \"code\",\n        \"doc\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"antoson\",\n      \"name\": \"Ondrej Antos\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36371990?v=4\",\n      \"profile\": \"https://github.com/antoson\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Bahnschrift\",\n      \"name\": \"Bahnschrift\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/31170809?v=4\",\n      \"profile\": \"https://github.com/Bahnschrift\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jakeboone02\",\n      \"name\": \"Jake Boone\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/366438?v=4\",\n      \"profile\": \"https://github.com/jakeboone02\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"kapsiR\",\n      \"name\": \"kapsiR\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7165033?v=4\",\n      \"profile\": \"https://github.com/kapsiR\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"csrakowski\",\n      \"name\": \"Christiaan Rakowski\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1303967?v=4\",\n      \"profile\": \"https://github.com/csrakowski\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mosullivan93\",\n      \"name\": \"Mitchell J. O'Sullivan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7676935?v=4\",\n      \"profile\": \"https://github.com/mosullivan93\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"felpel\",\n      \"name\": \"Félix Pelletier\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5000004?v=4\",\n      \"profile\": \"https://github.com/felpel\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ralish\",\n      \"name\": \"Samuel D. Leslie\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3214803?v=4\",\n      \"profile\": \"https://nexiom.net/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"AjayKMehta\",\n      \"name\": \"Ajay Mehta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11180071?v=4\",\n      \"profile\": \"https://github.com/AjayKMehta\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"the-eduardo\",\n      \"name\": \"the-eduardo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40523695?v=4\",\n      \"profile\": \"https://github.com/the-eduardo\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"antonpiatek\",\n      \"name\": \"Anton Piatek\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/175077?v=4\",\n      \"profile\": \"https://github.com/antonpiatek\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"prodehghan\",\n      \"name\": \"Mohammad Dehghan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1384790?v=4\",\n      \"profile\": \"https://careers.stackoverflow.com/dehghan\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"bhagerty\",\n      \"name\": \"bhagerty\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7828454?v=4\",\n      \"profile\": \"https://github.com/bhagerty\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"CodyScavenger\",\n      \"name\": \"Cody Scavenger\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/94334877?v=4\",\n      \"profile\": \"https://github.com/CodyScavenger\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"FWest98\",\n      \"name\": \"Floris Westerman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1918658?v=4\",\n      \"profile\": \"http://fwest98.nl/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"mjcarman\",\n      \"name\": \"Michael Carman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/121028?v=4\",\n      \"profile\": \"https://github.com/mjcarman\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"entr0pia\",\n      \"name\": \"风沐白\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/30486766?v=4\",\n      \"profile\": \"https://github.com/entr0pia\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"schallm\",\n      \"name\": \"Michael T. Schall\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/331167?v=4\",\n      \"profile\": \"https://github.com/schallm\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"craiglpeters\",\n      \"name\": \"Craig Peters\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9445180?v=4\",\n      \"profile\": \"https://github.com/craiglpeters\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"dorian-li\",\n      \"name\": \"Dongyu Li\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/49279922?v=4\",\n      \"profile\": \"https://github.com/dorian-li\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"cyberbliss\",\n      \"name\": \"Stephen Judd\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5401528?v=4\",\n      \"profile\": \"https://github.com/cyberbliss\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"douugdev\",\n      \"name\": \"Douglas Silva\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/59324692?v=4\",\n      \"profile\": \"https://douug.dev\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"BoseSj\",\n      \"name\": \"SJ Basak\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/58129377?v=4\",\n      \"profile\": \"https://github.com/BoseSj\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"treed\",\n      \"name\": \"Ted Reed\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/71910?v=4\",\n      \"profile\": \"http://tedreed.info\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"asportnoy\",\n      \"name\": \"Albert Portnoy\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/14863373?v=4\",\n      \"profile\": \"http://albertp.dev\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Lemorz56\",\n      \"name\": \"Sebastian\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1346676?v=4\",\n      \"profile\": \"https://www.msbrg.net/\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mirsella\",\n      \"name\": \"Lucas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/45905567?v=4\",\n      \"profile\": \"https://github.com/mirsella\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ethansocal\",\n      \"name\": \"Ethan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/79533577?v=4\",\n      \"profile\": \"https://github.com/ethansocal\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"astronaako\",\n      \"name\": \"Mohamed Naamy\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/18577543?v=4\",\n      \"profile\": \"https://github.com/astronaako\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"bend-n\",\n      \"name\": \"bendn\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/70787919?v=4\",\n      \"profile\": \"http://bend-n.github.io\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"davidanthoff\",\n      \"name\": \"David Anthoff\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1036561?v=4\",\n      \"profile\": \"http://www.david-anthoff.com\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jooooel\",\n      \"name\": \"jooooel\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9303280?v=4\",\n      \"profile\": \"https://github.com/jooooel\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"maxlandon\",\n      \"name\": \"maxlandon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/25826036?v=4\",\n      \"profile\": \"https://github.com/maxlandon\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"lino-levan\",\n      \"name\": \"Lino Le Van\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11367844?v=4\",\n      \"profile\": \"https://linolevan.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"dvlprJobayer\",\n      \"name\": \"Jobayer Ahammed Patwary\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/76583359?v=4\",\n      \"profile\": \"https://github.com/dvlprJobayer\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"NoF0rte\",\n      \"name\": \"NoF0rte\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/64100993?v=4\",\n      \"profile\": \"https://github.com/NoF0rte\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"LNKLEO\",\n      \"name\": \"LNKLEO\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10334184?v=4\",\n      \"profile\": \"https://github.com/LNKLEO\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"kamfaima\",\n      \"name\": \"kamfaima\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/23546392?v=4\",\n      \"profile\": \"https://github.com/kamfaima\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"dhrdlicka\",\n      \"name\": \"David Hrdlička\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13226155?v=4\",\n      \"profile\": \"https://github.com/dhrdlicka\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"davidcourtney\",\n      \"name\": \"David Courtney\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1019134?v=4\",\n      \"profile\": \"http://davidcourtney.com\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Jensdevloo\",\n      \"name\": \"jensdevloo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2276152?v=4\",\n      \"profile\": \"https://github.com/Jensdevloo\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"thomasdoerr\",\n      \"name\": \"Thomas Dörr\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6919685?v=4\",\n      \"profile\": \"https://github.com/thomasdoerr\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"SvenAelterman\",\n      \"name\": \"Sven Aelterman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17446043?v=4\",\n      \"profile\": \"https://blog.aelterman.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"CodexLink\",\n      \"name\": \"Janrey Licas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5953927?v=4\",\n      \"profile\": \"https://github.com/CodexLink\",\n      \"contributions\": [\n        \"design\",\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"padilo\",\n      \"name\": \"Pablo Díaz-López\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/783959?v=4\",\n      \"profile\": \"https://github.com/padilo\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"DarkMagicSource\",\n      \"name\": \"Caitlyn Williams\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35950530?v=4\",\n      \"profile\": \"https://github.com/DarkMagicSource\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"gork3n\",\n      \"name\": \"Christopher Henderson\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1086155?v=4\",\n      \"profile\": \"https://github.com/gork3n\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"cabauman\",\n      \"name\": \"Colt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6819362?v=4\",\n      \"profile\": \"https://www.coltbauman.com\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"craftzneko\",\n      \"name\": \"craftzneko\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/662108?v=4\",\n      \"profile\": \"https://github.com/craftzneko\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"atlanswer\",\n      \"name\": \"甘亭\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17683244?v=4\",\n      \"profile\": \"http://waferlab.dev\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Mertsch\",\n      \"name\": \"Mertsch\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9402861?v=4\",\n      \"profile\": \"https://github.com/Mertsch\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"marc2332\",\n      \"name\": \"Marc Espín\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/38158676?v=4\",\n      \"profile\": \"https://mespin.me/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"ksdpmx\",\n      \"name\": \"jasonz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3256083?v=4\",\n      \"profile\": \"https://github.com/ksdpmx\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"bsiegert\",\n      \"name\": \"Benny Siegert\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/866330?v=4\",\n      \"profile\": \"https://bentsukun.ch\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"kema-dev\",\n      \"name\": \"kema\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/54537427?v=4\",\n      \"profile\": \"http://www.kemadev.fr/fr/\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mavaddat\",\n      \"name\": \"Mavaddat Javid\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5055400?v=4\",\n      \"profile\": \"http://mavaddat.ca\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"iavael\",\n      \"name\": \"Iavael\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/905853?v=4\",\n      \"profile\": \"https://iavael.name/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Kushal-Chandar\",\n      \"name\": \"Kushal-Chandar\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/83660514?v=4\",\n      \"profile\": \"https://github.com/Kushal-Chandar\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"BigBear0812\",\n      \"name\": \"Matthew Miller\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2429638?v=4\",\n      \"profile\": \"http://www.project-miller.com/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"javidcf\",\n      \"name\": \"Javier Dehesa\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1098280?v=4\",\n      \"profile\": \"https://github.com/javidcf\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"alexvy86\",\n      \"name\": \"Alex Villarreal\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/716334?v=4\",\n      \"profile\": \"https://alex-v.blog/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"krzysdz\",\n      \"name\": \"krzysdz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/12915102?v=4\",\n      \"profile\": \"https://github.com/krzysdz\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"BasLijten\",\n      \"name\": \"Bas Lijten\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11842067?v=4\",\n      \"profile\": \"http://blog.baslijten.com\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ParkerM\",\n      \"name\": \"Parker Mauney\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5124113?v=4\",\n      \"profile\": \"https://github.com/ParkerM\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"gbrusella\",\n      \"name\": \"Gonzalo Brusella\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/115679?v=4\",\n      \"profile\": \"http://www.brusella.com.ar\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"krokofant\",\n      \"name\": \"Emil Sundin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5908498?v=4\",\n      \"profile\": \"https://github.com/krokofant\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"dysuby\",\n      \"name\": \"dysuby\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/26317510?v=4\",\n      \"profile\": \"http://dysuby.github.io\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"dorokhin-bohdan\",\n      \"name\": \"Bohdan Dorokhin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/24988081?v=4\",\n      \"profile\": \"https://github.com/dorokhin-bohdan\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"CY-Pan\",\n      \"name\": \"Ad Red\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/59761962?v=4\",\n      \"profile\": \"https://github.com/CY-Pan\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"nopeless\",\n      \"name\": \"nopeless\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/38830903?v=4\",\n      \"profile\": \"https://github.com/nopeless\",\n      \"contributions\": [\n        \"code\",\n        \"doc\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"vinhloc30796\",\n      \"name\": \"Loc Nguyen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19675202?v=4\",\n      \"profile\": \"https://linkedin.com/in/vinhloc30796\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Coder-Tavi\",\n      \"name\": \"Tavi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/66774833?v=4\",\n      \"profile\": \"https://tavis.page\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"NicholasDawson\",\n      \"name\": \"Nick Dawson\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/37987430?v=4\",\n      \"profile\": \"http://ndawson.me\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jntrnr\",\n      \"name\": \"JT\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/547158?v=4\",\n      \"profile\": \"https://www.jntrnr.com/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"ChandanChainani\",\n      \"name\": \"ChandanChainani\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/28807775?v=4\",\n      \"profile\": \"https://github.com/ChandanChainani\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jenspinney\",\n      \"name\": \"Jen Spinney\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3200507?v=4\",\n      \"profile\": \"https://github.com/jenspinney\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"rotu\",\n      \"name\": \"Dan Rose\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/119948?v=4\",\n      \"profile\": \"https://github.com/rotu\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"darthwalsh\",\n      \"name\": \"Carl Walsh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2829438?v=4\",\n      \"profile\": \"https://carlwa.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ercpereda\",\n      \"name\": \"Ernesto R. C. Pereda\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13546685?v=4\",\n      \"profile\": \"https://github.com/ercpereda\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"0Ky\",\n      \"name\": \"ｃｒｙｐｔｉｘ\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16103757?v=4\",\n      \"profile\": \"https://github.com/0Ky\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ehawman\",\n      \"name\": \"Evan Hawman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/52979227?v=4\",\n      \"profile\": \"https://github.com/ehawman\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"ZerdoX-x\",\n      \"name\": \"Mark Lansky\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/49815452?v=4\",\n      \"profile\": \"https://zerdox.dev\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"pulsation\",\n      \"name\": \"pulsation\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1838397?v=4\",\n      \"profile\": \"https://github.com/pulsation\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"oriionn\",\n      \"name\": \"orionsource\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/38093786?v=4\",\n      \"profile\": \"https://oriondev.fr\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"CesarGBkR\",\n      \"name\": \"Cesar Garduño\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/99093357?v=4\",\n      \"profile\": \"https://github.com/CesarGBkR\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Adi-vig\",\n      \"name\": \"Aditya Sakhare\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/123308369?v=4\",\n      \"profile\": \"https://github.com/Adi-vig\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"deepak-dev-96\",\n      \"name\": \"Deepak Dev\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/134447761?v=4\",\n      \"profile\": \"https://github.com/deepak-dev-96\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"warrenbuckley\",\n      \"name\": \"Warren Buckley\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1389894?v=4\",\n      \"profile\": \"http://creativewebspecialist.co.uk\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"LunarMarathon\",\n      \"name\": \"LunarMarathon\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/113847439?v=4\",\n      \"profile\": \"https://github.com/LunarMarathon\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ginglis13\",\n      \"name\": \"Gavin Inglis\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43075615?v=4\",\n      \"profile\": \"https://ginglis.me\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jaliyaudagedara\",\n      \"name\": \"Jaliya Udagedara\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5653381?v=4\",\n      \"profile\": \"http://jaliyaudagedara.blogspot.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"BPplays\",\n      \"name\": \"BPplays\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/58504799?v=4\",\n      \"profile\": \"https://github.com/BPplays\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"mateusz-bajorek\",\n      \"name\": \"Mateusz Bajorek\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11185738?v=4\",\n      \"profile\": \"https://github.com/mateusz-bajorek\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"joshbduncan\",\n      \"name\": \"Josh Duncan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/44387852?v=4\",\n      \"profile\": \"http://joshbduncan.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"princesaini\",\n      \"name\": \"Prince Saini\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/25565506?v=4\",\n      \"profile\": \"https://github.com/princesaini\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"fabriciojlm\",\n      \"name\": \"fabriciojlm\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/70244182?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/fabriciojuliano/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"SriRamanujam\",\n      \"name\": \"Sri Ramanujam\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2983875?v=4\",\n      \"profile\": \"https://github.com/SriRamanujam\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Juneezee\",\n      \"name\": \"Eng Zer Jun\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/20135478?v=4\",\n      \"profile\": \"https://github.com/Juneezee\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"AlexJPotter\",\n      \"name\": \"Alex Potter\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/14200888?v=4\",\n      \"profile\": \"https://alexpotter.dev\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mishmanners\",\n      \"name\": \"Michelle Mannering\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36594527?v=4\",\n      \"profile\": \"http://mishmanners.info\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"paulomorgado\",\n      \"name\": \"Paulo Morgado\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/470455?v=4\",\n      \"profile\": \"https://github.com/paulomorgado\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"joadoumie\",\n      \"name\": \"joadoumie\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/98557455?v=4\",\n      \"profile\": \"https://github.com/joadoumie\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"flanakin\",\n      \"name\": \"Michael Flanakin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/399533?v=4\",\n      \"profile\": \"http://about.me/flanakin\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"thiagoszbarros\",\n      \"name\": \"Thiago Barros\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/88802518?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/thiagobarros95/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"TendTo\",\n      \"name\": \"Tend\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/65033249?v=4\",\n      \"profile\": \"https://github.com/TendTo\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"KibbeWater\",\n      \"name\": \"Snow\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35224538?v=4\",\n      \"profile\": \"https://kibbewater.com\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"randombenj\",\n      \"name\": \"Benj Fassbind\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5184499?v=4\",\n      \"profile\": \"https://github.com/randombenj\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"liudonghua123\",\n      \"name\": \"liudonghua\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2276718?v=4\",\n      \"profile\": \"http://blog.liudonghua.top\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Somoy73\",\n      \"name\": \"Somoy Subandhu\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40368688?v=4\",\n      \"profile\": \"http://somoy.me\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"oleksbabieiev\",\n      \"name\": \"Oleksandr Babieiev\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/64398691?v=4\",\n      \"profile\": \"https://github.com/oleksbabieiev\",\n      \"contributions\": [\n        \"code\",\n        \"doc\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"mrbeardad\",\n      \"name\": \"Heache Bear\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/54128430?v=4\",\n      \"profile\": \"https://github.com/mrbeardad\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ChrisNSki\",\n      \"name\": \"Christopher Narowski\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/125232146?v=4\",\n      \"profile\": \"http://ensif.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"sino1641\",\n      \"name\": \"Sin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13870295?v=4\",\n      \"profile\": \"https://github.com/sino1641\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"kkk669\",\n      \"name\": \"Kenta Kubo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/601636?v=4\",\n      \"profile\": \"https://kebo.xyz\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mfedatto\",\n      \"name\": \"MFedatto\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5623739?v=4\",\n      \"profile\": \"http://mfedatto.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"RiikkaDream\",\n      \"name\": \"Riikka\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/56921531?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/riikka-l-861694b2/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"srpmtt\",\n      \"name\": \"srpmtt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11175503?v=4\",\n      \"profile\": \"https://github.com/srpmtt\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Chris-Johnston\",\n      \"name\": \"Chris Johnston\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16418643?v=4\",\n      \"profile\": \"https://chris-johnston.me\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Daimonion1980\",\n      \"name\": \"Thomas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/12880413?v=4\",\n      \"profile\": \"https://github.com/Daimonion1980\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"VEERT00X\",\n      \"name\": \"Veko\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/72668825?v=4\",\n      \"profile\": \"https://veert00x.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"lucascosti\",\n      \"name\": \"Lucas Costi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4434330?v=4\",\n      \"profile\": \"https://lucascosti.com\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"gergelyk\",\n      \"name\": \"Grzegorz Krasoń\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11185582?v=4\",\n      \"profile\": \"http://krason.dev/\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"rockyoung\",\n      \"name\": \"rockyoung\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1207971?v=4\",\n      \"profile\": \"https://github.com/rockyoung\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"shravanasati\",\n      \"name\": \"Shravan Asati\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/69118069?v=4\",\n      \"profile\": \"https://github.com/shravanasati\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"lzecca78\",\n      \"name\": \"Luca Zecca\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3881844?v=4\",\n      \"profile\": \"https://github.com/lzecca78\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jreilly-lukava\",\n      \"name\": \"Joshua Reilly\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/30353736?v=4\",\n      \"profile\": \"https://github.com/jreilly-lukava\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ivan-the-terrible\",\n      \"name\": \"Ivan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/56458442?v=4\",\n      \"profile\": \"https://ivan-the-terrible.github.io/\",\n      \"contributions\": [\n        \"design\",\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"mountcount\",\n      \"name\": \"mountcount\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/166301065?v=4\",\n      \"profile\": \"https://github.com/mountcount\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Bondrake\",\n      \"name\": \"Bondrake\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11696?v=4\",\n      \"profile\": \"https://github.com/Bondrake\",\n      \"contributions\": [\n        \"design\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"R00dRallec\",\n      \"name\": \"R00dRallec\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9081954?v=4\",\n      \"profile\": \"https://github.com/R00dRallec\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"publicfacingusername\",\n      \"name\": \"Justin Wolfington\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13956145?v=4\",\n      \"profile\": \"https://github.com/publicfacingusername\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jtracey93\",\n      \"name\": \"Jack Tracey\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/41163455?v=4\",\n      \"profile\": \"https://bio.link/jacktracey\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"MarkDaveny\",\n      \"name\": \"MarkDaveny\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/168091250?v=4\",\n      \"profile\": \"https://github.com/MarkDaveny\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"tiwahu\",\n      \"name\": \"Timothy Huber\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/590564?v=4\",\n      \"profile\": \"http://www.tiwahu.com/\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"YashJM\",\n      \"name\": \"Yash Mistry\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/63824041?v=4\",\n      \"profile\": \"http://yashjmistry.me\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"jlabonski\",\n      \"name\": \"Jeffrey Labonski\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2981369?v=4\",\n      \"profile\": \"https://github.com/jlabonski\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"herbygillot\",\n      \"name\": \"Herby Gillot\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/618376?v=4\",\n      \"profile\": \"https://github.com/herbygillot\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"arjan-s\",\n      \"name\": \"arjan-s\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10400299?v=4\",\n      \"profile\": \"https://github.com/arjan-s\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"0323pin\",\n      \"name\": \"pin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/90570748?v=4\",\n      \"profile\": \"https://github.com/0323pin\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"FireIsGood\",\n      \"name\": \"FireIsGood\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/109556932?v=4\",\n      \"profile\": \"http://fireis.dev\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Joxtacy\",\n      \"name\": \"Jesper Hasselquist\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10127673?v=4\",\n      \"profile\": \"https://github.com/Joxtacy\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"aaronpowell\",\n      \"name\": \"Aaron Powell\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/434140?v=4\",\n      \"profile\": \"https://www.aaron-powell.com\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Dartypier\",\n      \"name\": \"Jacopo Zecchi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/22201626?v=4\",\n      \"profile\": \"https://github.com/Dartypier\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"rose-m\",\n      \"name\": \"Michael Rose\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4354632?v=4\",\n      \"profile\": \"https://github.com/rose-m\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"denehoffman\",\n      \"name\": \"Nathaniel D. Hoffman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36977879?v=4\",\n      \"profile\": \"http://denehoffman.com\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"michaelschwobe\",\n      \"name\": \"Michael Schwobe\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/926242?v=4\",\n      \"profile\": \"https://schwobe.dev\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Nibodhika\",\n      \"name\": \"Nibodhika\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/729967?v=4\",\n      \"profile\": \"https://github.com/Nibodhika\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"sassdawe\",\n      \"name\": \"David Sass\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10754765?v=4\",\n      \"profile\": \"http://davidsass.io\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"carehart\",\n      \"name\": \"Charlie Arehart\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/389746?v=4\",\n      \"profile\": \"http://www.carehart.org\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"aramikuto\",\n      \"name\": \"Aleksandr Kondrashov\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/116561995?v=4\",\n      \"profile\": \"https://github.com/aramikuto\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"kimsey0\",\n      \"name\": \"Jacob Bundgaard\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/984760?v=4\",\n      \"profile\": \"https://jacobbundgaard.dk\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ThisaruGuruge\",\n      \"name\": \"Thisaru Guruge\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40016057?v=4\",\n      \"profile\": \"https://thisaru.me\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"edwin-shdw\",\n      \"name\": \"Edwin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/62764562?v=4\",\n      \"profile\": \"https://github.com/edwin-shdw\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"jcdickinson\",\n      \"name\": \"Jonathan Dickinson\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/522465?v=4\",\n      \"profile\": \"https://dickinson.id\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"po1o\",\n      \"name\": \"Polo-François Poli\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5702825?v=4\",\n      \"profile\": \"https://github.com/po1o\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"EDIflyer\",\n      \"name\": \"EDIflyer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13610277?v=4\",\n      \"profile\": \"https://github.com/EDIflyer\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"felipebz\",\n      \"name\": \"Felipe Zorzo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/13829?v=4\",\n      \"profile\": \"https://felipezorzo.com.br\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"DeepSpace2\",\n      \"name\": \"Adi Vaknin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6841988?v=4\",\n      \"profile\": \"https://github.com/DeepSpace2\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"EladLeev\",\n      \"name\": \"Elad Leev\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/835319?v=4\",\n      \"profile\": \"https://leevs.dev/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Soyvolon\",\n      \"name\": \"Bounds\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16871668?v=4\",\n      \"profile\": \"https://github.com/Soyvolon\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Yash-Garg\",\n      \"name\": \"Yash Garg\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/33605526?v=4\",\n      \"profile\": \"http://yashgarg.dev\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"sarpuser\",\n      \"name\": \"Sarp User\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/23362324?v=4\",\n      \"profile\": \"https://github.com/sarpuser\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"clemyan\",\n      \"name\": \"Clement Yan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/41266433?v=4\",\n      \"profile\": \"https://github.com/clemyan\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"thep0y\",\n      \"name\": \"thep0y\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/51874567?v=4\",\n      \"profile\": \"https://github.com/thep0y\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"ClxUne09\",\n      \"name\": \"Artin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/175628107?v=4\",\n      \"profile\": \"https://github.com/ClxUne09\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"guspan-tanadi\",\n      \"name\": \"Guspan Tanadi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/36249910?v=4\",\n      \"profile\": \"https://github.com/guspan-tanadi\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"rocketraman\",\n      \"name\": \"Raman Gupta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/53049?v=4\",\n      \"profile\": \"http://vivosys.com\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"hsnabszhdn\",\n      \"name\": \"Hossein Abbasi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16090309?v=4\",\n      \"profile\": \"https://github.com/hsnabszhdn\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"kizivat\",\n      \"name\": \"David Kizivat\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/3535926?v=4\",\n      \"profile\": \"https://kizivat.eu\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mgrubb\",\n      \"name\": \"Michael Grubb\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/351301?v=4\",\n      \"profile\": \"https://github.com/mgrubb\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"oliviaBahr\",\n      \"name\": \"Olivia Bahr\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/98684296?v=4\",\n      \"profile\": \"https://github.com/oliviaBahr\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"garysassano\",\n      \"name\": \"Gary Sassano\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10464497?v=4\",\n      \"profile\": \"https://github.com/garysassano\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"ilaumjd\",\n      \"name\": \"Ilham AM\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/16514431?v=4\",\n      \"profile\": \"https://github.com/ilaumjd\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"trajano\",\n      \"name\": \"Archimedes Trajano\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/110627?v=4\",\n      \"profile\": \"https://trajano.net/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"devxpain\",\n      \"name\": \"devxpain\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/170700110?v=4\",\n      \"profile\": \"https://github.com/devxpain\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"AntoninRuan\",\n      \"name\": \"Antonin Ruan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43148004?v=4\",\n      \"profile\": \"https://www.antonin-ruan.fr\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"00ll00\",\n      \"name\": \"00ll00\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40747228?v=4\",\n      \"profile\": \"https://github.com/00ll00\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ernstc\",\n      \"name\": \"Ernesto Cianciotta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/130360?v=4\",\n      \"profile\": \"https://devnotes.ernstc.net/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"eelispeltola\",\n      \"name\": \"Eelis Peltola\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/15069074?v=4\",\n      \"profile\": \"https://github.com/eelispeltola\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"vshulcz\",\n      \"name\": \"Vlad Shulcz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/99616188?v=4\",\n      \"profile\": \"https://github.com/vshulcz\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Silzinc\",\n      \"name\": \"Silzinc\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/128738169?v=4\",\n      \"profile\": \"https://github.com/Silzinc\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Hampter\",\n      \"name\": \"Noah Springer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/23213489?v=4\",\n      \"profile\": \"https://github.com/Hampter\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"dusktreader\",\n      \"name\": \"Tucker Beck\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/713676?v=4\",\n      \"profile\": \"https://github.com/dusktreader\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Pietrucci-Blacher\",\n      \"name\": \"Sunshio\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/38607067?v=4\",\n      \"profile\": \"https://mpb-dev.fr/\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"pashagolub\",\n      \"name\": \"Pavlo Golub\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9463113?v=4\",\n      \"profile\": \"https://pashagolub.github.io/blog\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"heaths\",\n      \"name\": \"Heath Stewart\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1532486?v=4\",\n      \"profile\": \"https://heaths.dev\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"HypheX\",\n      \"name\": \"Xelph\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/29693543?v=4\",\n      \"profile\": \"https://xelph.me\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"TristanLeclair\",\n      \"name\": \"Tristan Leclair-Vani\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/60434271?v=4\",\n      \"profile\": \"https://tristanleclair.github.io/personal-website/index.html\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"vil02\",\n      \"name\": \"Piotr Idzik\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/65706193?v=4\",\n      \"profile\": \"https://github.com/vil02\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"wiyco\",\n      \"name\": \"wiyco\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/72733890?v=4\",\n      \"profile\": \"https://wiyco.dev\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"abhro\",\n      \"name\": \"abhro\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/5664668?v=4\",\n      \"profile\": \"https://github.com/abhro\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"spg-iwilson\",\n      \"name\": \"Ivan Wilson\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/25376734?v=4\",\n      \"profile\": \"https://sharepointgurus.net\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"mdanish-kh\",\n      \"name\": \"Muhammad Danish\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/88161975?v=4\",\n      \"profile\": \"https://github.com/mdanish-kh\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"BoscoDomingo\",\n      \"name\": \"Bosco Domingo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/46006784?v=4\",\n      \"profile\": \"https://dub.sh/boscodomingo\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Edu4rdSHL\",\n      \"name\": \"Eduard Tolosa\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/32582878?v=4\",\n      \"profile\": \"https://edu4rdshl.dev\",\n      \"contributions\": [\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"JamesAndrewJackson13\",\n      \"name\": \"James Jackson\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/27647566?v=4\",\n      \"profile\": \"https://github.com/JamesAndrewJackson13\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Mr-Vipi\",\n      \"name\": \"Jul Guga\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/58825526?v=4\",\n      \"profile\": \"https://github.com/Mr-Vipi\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"tiaoxizhan\",\n      \"name\": \"tiaoxizhan\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/178074436?v=4\",\n      \"profile\": \"http://txzhan.io\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"chrisant996\",\n      \"name\": \"Chris Antos\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17440311?v=4\",\n      \"profile\": \"https://github.com/chrisant996\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"rbleattler\",\n      \"name\": \"Robert Bleattler\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/40604784?v=4\",\n      \"profile\": \"https://robertbleattler.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"d3v2a\",\n      \"name\": \"dev2a\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1815655?v=4\",\n      \"profile\": \"https://artis-auxilium.fr/fr\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"luisegarduno\",\n      \"name\": \"Luis\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/30121656?v=4\",\n      \"profile\": \"http://gardunos.tech\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"tleepa\",\n      \"name\": \"Leepa\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7734919?v=4\",\n      \"profile\": \"https://github.com/tleepa\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"raylu\",\n      \"name\": \"raylu\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/90059?v=4\",\n      \"profile\": \"https://blog.raylu.net\",\n      \"contributions\": [\n        \"code\",\n        \"doc\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"lechwolowski\",\n      \"name\": \"Lech Wołowski\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/33866950?v=4\",\n      \"profile\": \"https://github.com/lechwolowski\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"OwlBurst\",\n      \"name\": \"Owl Burst\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/158167545?v=4\",\n      \"profile\": \"https://github.com/OwlBurst\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"RubixDev\",\n      \"name\": \"Silas Groh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35602040?v=4\",\n      \"profile\": \"http://rubixdev.de\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mwiedemeyer\",\n      \"name\": \"Marco Wiedemeyer\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4295189?v=4\",\n      \"profile\": \"https://mwiede.me/blog\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"0-0-1-0-1-0-1-0\",\n      \"name\": \"0-0-1-0-1-0-1-0\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/43226073?v=4\",\n      \"profile\": \"https://github.com/0-0-1-0-1-0-1-0\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"player131007\",\n      \"name\": \"player131007\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/77326303?v=4\",\n      \"profile\": \"https://github.com/player131007\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"kaien07\",\n      \"name\": \"kaien07\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/160471571?v=4\",\n      \"profile\": \"https://github.com/kaien07\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"BusHero\",\n      \"name\": \"Cervac Petru\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/24370515?v=4\",\n      \"profile\": \"https://github.com/BusHero\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"Marukome0743\",\n      \"name\": \"マルコメ\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/146040408?v=4\",\n      \"profile\": \"https://github.com/Marukome0743\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mreinhardt\",\n      \"name\": \"Michael Reinhardt\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/582461?v=4\",\n      \"profile\": \"https://github.com/mreinhardt\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"AspectBruise09\",\n      \"name\": \"Artin\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/141767586?v=4\",\n      \"profile\": \"https://github.com/AspectBruise09\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"b-simjoo\",\n      \"name\": \"Behnam Simjoo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/117530839?v=4\",\n      \"profile\": \"http://bsimjoo.pcworms.ir\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"plamendelchev\",\n      \"name\": \"Plamen Delchev\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/25668366?v=4\",\n      \"profile\": \"https://github.com/plamendelchev\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"beaualbritton\",\n      \"name\": \"beau albritton\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/112587801?v=4\",\n      \"profile\": \"https://github.com/beaualbritton\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Cierra-Runis\",\n      \"name\": \"Cierra-Runis\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/29329988?v=4\",\n      \"profile\": \"https://note-of-me.top\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"jasonm23\",\n      \"name\": \"Jason Milkins\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/71587?v=4\",\n      \"profile\": \"https://github.com/jasonm23\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"arjunrbery\",\n      \"name\": \"arjunrbery\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/20059577?v=4\",\n      \"profile\": \"http://www.arb.dev\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"JamBalaya56562\",\n      \"name\": \"Jam Balaya\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/88115388?v=4\",\n      \"profile\": \"https://github.com/JamBalaya56562\",\n      \"contributions\": [\n        \"doc\",\n        \"code\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"RichLewis007\",\n      \"name\": \"Rich Lewis\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1149213?v=4\",\n      \"profile\": \"https://github.com/RichLewis007\",\n      \"contributions\": [\n        \"doc\",\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"Gijsreyn\",\n      \"name\": \"Gijs Reijn\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/26114636?v=4\",\n      \"profile\": \"https://gijsreijn.medium.com/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"mikelolasagasti\",\n      \"name\": \"Mikel Olasagasti Uranga\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/773148?v=4\",\n      \"profile\": \"https://mikel.olasagasti.info\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"mkvlrn\",\n      \"name\": \"mkvlrn\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/186238078?v=4\",\n      \"profile\": \"https://github.com/mkvlrn\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"iandunn\",\n      \"name\": \"Ian Dunn\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/484068?v=4\",\n      \"profile\": \"https://iandunn.name\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"sanki92\",\n      \"name\": \"Sankalp Tripathi\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/70330866?v=4\",\n      \"profile\": \"https://github.com/sanki92\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"MariusStorhaug\",\n      \"name\": \"Marius Storhaug\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17722253?v=4\",\n      \"profile\": \"https://github.com/PSModule\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ADIX7\",\n      \"name\": \"Kovács Ádám\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/10939090?v=4\",\n      \"profile\": \"https://github.com/ADIX7\",\n      \"contributions\": [\n        \"doc\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"spidersouris\",\n      \"name\": \"Enzo Doyen\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/7102007?v=4\",\n      \"profile\": \"https://www.edoyen.com/\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Pinta365\",\n      \"name\": \"Pinta\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/19735646?v=4\",\n      \"profile\": \"https://pinta.land\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"scop\",\n      \"name\": \"Ville Skyttä\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/109152?v=4\",\n      \"profile\": \"https://github.com/scop\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"anujsrc\",\n      \"name\": \"Anuj Kumar\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/1001682?v=4\",\n      \"profile\": \"http://linkedin.com/in/anujsays\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"ValerioCeccarelli\",\n      \"name\": \"Valerio Ceccarelli\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/42637334?v=4\",\n      \"profile\": \"https://github.com/ValerioCeccarelli\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"jvsca\",\n      \"name\": \"Juan Svaikauskas\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/2821731?v=4\",\n      \"profile\": \"https://github.com/jvsca\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"johnstegeman\",\n      \"name\": \"John Stegeman\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6601691?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/johnstegeman/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"gorfey\",\n      \"name\": \"Luke Van De Weghe\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/39035228?v=4\",\n      \"profile\": \"https://github.com/gorfey\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"stmach\",\n      \"name\": \"Stefan Mach\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/33124232?v=4\",\n      \"profile\": \"https://github.com/stmach\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"squaricdot\",\n      \"name\": \"Olmo Rupert\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/4513505?v=4\",\n      \"profile\": \"http://squaricdot.com\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"IsaacFG2\",\n      \"name\": \"IsaacFG2\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/147211323?v=4\",\n      \"profile\": \"https://github.com/IsaacFG2\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"kostadin-tonchekliev\",\n      \"name\": \"Kostadin Tonchekliev\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/95169764?v=4\",\n      \"profile\": \"https://github.com/kostadin-tonchekliev\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"soroshsabz\",\n      \"name\": \"soroshsabz\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/17947618?v=4\",\n      \"profile\": \"https://github.com/soroshsabz\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"yblossier\",\n      \"name\": \"Yoann BLOSSIER\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/60755917?v=4\",\n      \"profile\": \"https://blog.toenn-vaot.fr\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"kvokka\",\n      \"name\": \"Mikhail Beliakov\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/15954013?v=4\",\n      \"profile\": \"https://kvokka.github.io/\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"MrRainbow0704\",\n      \"name\": \"Marco Simone\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/95081253?v=4\",\n      \"profile\": \"https://github.com/MrRainbow0704\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"sbeardsley\",\n      \"name\": \"sbeardsley\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/6288131?v=4\",\n      \"profile\": \"https://github.com/sbeardsley\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"maxvictor\",\n      \"name\": \"Max Victor\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/11591713?v=4\",\n      \"profile\": \"https://www.linkedin.com/in/maxvictor\",\n      \"contributions\": [\n        \"design\"\n      ]\n    },\n    {\n      \"login\": \"adackny\",\n      \"name\": \"Adackny Castillo\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/61998238?v=4\",\n      \"profile\": \"https://github.com/adackny\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"aeriondyseti\",\n      \"name\": \"K Whiteside\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/24901014?v=4\",\n      \"profile\": \"https://github.com/aeriondyseti\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"dadahsueh\",\n      \"name\": \"Dada Hsueh\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/26140722?v=4\",\n      \"profile\": \"http://dadahsueh.vercel.app\",\n      \"contributions\": [\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"dohzya\",\n      \"name\": \"Étienne Vallette d'Osia\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/9595?v=4\",\n      \"profile\": \"https://github.com/dohzya\",\n      \"contributions\": [\n        \"code\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"Eckii24\",\n      \"name\": \"Eckii24\",\n      \"avatar_url\": \"https://avatars.githubusercontent.com/u/35373554?v=4\",\n      \"profile\": \"https://github.com/Eckii24\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"doc\"\n      ]\n    }\n  ],\n  \"contributorsPerLine\": 7,\n  \"skipCi\": true,\n  \"commitType\": \"docs\"\n}\n"
  },
  {
    "path": ".commitlintrc.yml",
    "content": "---\nextends:\n  - '@commitlint/config-conventional'\nrules:\n  body-max-line-length:\n    - 2\n    - always\n    - 200\n  type-enum:\n    - 2\n    - always\n    - - chore\n      - ci\n      - docs\n      - feat\n      - fix\n      - perf\n      - refactor\n      - revert\n      - style\n      - test\n      - theme\n"
  },
  {
    "path": ".config/configuration.winget",
    "content": "# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2\nproperties:\n  resources:\n    - resource: Microsoft.WinGet.DSC/WinGetPackage\n      directives:\n        description: Install Visual Studio Code\n      settings:\n        id: Microsoft.VisualStudioCode\n        source: winget\n    - resource: Microsoft.WinGet.DSC/WinGetPackage\n      id: golang\n      directives:\n        description: Install Golang\n      settings:\n        id: GoLang.Go\n        source: winget\n    - resource: Microsoft.WinGet.DSC/WinGetPackage\n      dependsOn: [golang]\n      directives:\n        description: Install golangci-lint\n      settings:\n        id: GolangCI.golangci-lint\n        source: winget\n    - resource: Microsoft.WinGet.DSC/WinGetPackage\n      directives:\n        description: Install NodeJS\n        securityContext: elevated\n      settings:\n        id: OpenJS.NodeJS\n        source: winget\n  configurationVersion: 0.2.0\n"
  },
  {
    "path": ".devcontainer/Dockerfile",
    "content": "# See here for image contents: https://github.com/devcontainers/images/blob/main/src/go/.devcontainer/Dockerfile\n\n# [Choice] Go version: 1, 1.24, 1.25, 1-trixie, 1.24-trixie, 1.25-trixie, 1-bookworm, 1.24-bookworm, 1.25-bookworm, 1-bullseye, 1.24-bullseye, 1.25-bullseye\nARG VARIANT=1-trixie\nFROM mcr.microsoft.com/vscode/devcontainers/go:${VARIANT}\n\n# [Choice] Node.js version: none, lts/*, 24, 22, 20\nARG NODE_VERSION=\"none\"\nRUN if [ \"${NODE_VERSION}\" != \"none\" ]; then su vscode -c \"umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1\"; fi\n\n# Install powershell\nARG PS_VERSION=\"7.5.4\"\n# powershell-7.5.4-linux-x64.tar.gz\n# powershell-7.5.4-linux-arm64.tar.gz\nRUN ARCH=\"$(dpkg --print-architecture)\"; \\\n    if [ \"${ARCH}\" = \"amd64\" ]; then \\\n        PS_BIN=\"v$PS_VERSION/powershell-$PS_VERSION-linux-x64.tar.gz\"; \\\n    elif [ \"${ARCH}\" = \"arm64\" ]; then \\\n        PS_BIN=\"v$PS_VERSION/powershell-$PS_VERSION-linux-arm64.tar.gz\"; \\\n    elif [ \"${ARCH}\" = \"armhf\" ]; then \\\n        PS_BIN=\"v$PS_VERSION/powershell-$PS_VERSION-linux-arm32.tar.gz\"; \\\n    fi; \\\n    wget https://github.com/PowerShell/PowerShell/releases/download/$PS_BIN -O pwsh.tar.gz; \\\n    mkdir /usr/local/pwsh && \\\n    tar Cxvfz /usr/local/pwsh pwsh.tar.gz && \\\n    rm pwsh.tar.gz && \\\n    chmod +x /usr/local/pwsh/pwsh\n\nENV PATH=$PATH:/usr/local/pwsh\n\nRUN echo 'deb http://download.opensuse.org/repositories/shells:/fish:/release:/4/Debian_13/ /' | tee /etc/apt/sources.list.d/shells:fish:release:4.list; \\\n    curl -fsSL https://download.opensuse.org/repositories/shells:fish:release:4/Debian_13/Release.key | gpg --dearmor | tee /etc/apt/trusted.gpg.d/shells_fish_release_4.gpg > /dev/null; \\\n    apt-get update && export DEBIAN_FRONTEND=noninteractive \\\n    && apt-get install -y --no-install-recommends \\\n    fish \\\n    tmux \\\n    fzf \\\n    && apt-get clean\n\nARG USERNAME=vscode\n\n# NOTE: devcontainers are Linux-only at this time but when\n# Windows or Darwin is supported someone will need to improve\n# the code logic above.\n\n# Setup a neat little PowerShell experience\nRUN pwsh -Command Install-Module posh-git -Scope AllUsers -Force; \\\n    pwsh -Command Install-Module z -Scope AllUsers -Force; \\\n    pwsh -Command Install-Module PSFzf -Scope AllUsers -Force; \\\n    pwsh -Command Install-Module Terminal-Icons -Scope AllUsers -Force;\n\n# add the oh-my-posh path to the PATH variable\nENV PATH=\"$PATH:/home/${USERNAME}/bin\"\n\n# Deploy oh-my-posh prompt to Powershell:\nCOPY Microsoft.PowerShell_profile.ps1 /home/${USERNAME}/.config/powershell/Microsoft.PowerShell_profile.ps1\n\n# Deploy oh-my-posh prompt to Fish:\nCOPY config.fish /home/${USERNAME}/.config/fish/config.fish\n\n# Everything runs as root during build time, so we want\n# to make sure the vscode user can edit these paths too:\nRUN chmod 777 -R /home/${USERNAME}/.config\n\n# Override vscode's own Bash prompt with oh-my-posh:\nRUN sed -i 's/^__bash_prompt$/#&/' /home/${USERNAME}/.bashrc && \\\n    echo \"eval \\\"\\$(oh-my-posh init bash)\\\"\" >> /home/${USERNAME}/.bashrc\n\n# Override vscode's own ZSH prompt with oh-my-posh:\nRUN echo \"eval \\\"\\$(oh-my-posh init zsh)\\\"\" >> /home/${USERNAME}/.zshrc\n\n# Set container timezone:\nARG TZ=\"UTC\"\nRUN ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime\n\n# [Optional] Uncomment the next line to use go get to install anything else you need\n# RUN go get -x github.com/JanDeDobbeleer/battery\n\n# [Optional] Uncomment this line to install global node packages.\n# RUN su vscode -c \"source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>\" 2>&1\n"
  },
  {
    "path": ".devcontainer/Microsoft.PowerShell_profile.ps1",
    "content": "Import-Module posh-git\nImport-Module PSFzf -ArgumentList 'Ctrl+t', 'Ctrl+r'\nImport-Module z\nImport-Module Terminal-Icons\n\nSet-PSReadlineKeyHandler -Key Tab -Function MenuComplete\n\n$env:POSH_GIT_ENABLED=$true\noh-my-posh init pwsh | Invoke-Expression\n"
  },
  {
    "path": ".devcontainer/config.fish",
    "content": "# Activate oh-my-posh prompt:\noh-my-posh init fish | source\n"
  },
  {
    "path": ".devcontainer/devcontainer.json",
    "content": "// For format details, see https://containers.dev/implementors/json_reference.\n// For config options, see the README at: https://github.com/devcontainers/images/tree/main/src/go\n{\n  \"name\": \"oh-my-posh\",\n  \"build\": {\n    \"dockerfile\": \"Dockerfile\",\n    \"args\": {\n      // Update the VARIANT arg to pick a version of Go: 1, 1.24, 1.25\n      // Append -trixie, -bookworm or -bullseye to pin to an OS version.\n      \"VARIANT\": \"2-1.25-trixie\",\n\n      // Override me with your own timezone:\n      \"TZ\": \"UTC\",\n      // Use one of the \"TZ database name\" entries from:\n      // https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\n\n      \"NODE_VERSION\": \"lts/*\",\n      //Powershell version\n      \"PS_VERSION\": \"7.5.4\"\n    }\n  },\n  \"runArgs\": [\n    \"--cap-add=SYS_PTRACE\",\n    \"--security-opt\",\n    \"seccomp=unconfined\",\n    \"--security-opt\",\n    \"label=disable\"\n  ],\n  \"containerEnv\": {\n    \"HOME\": \"/home/vscode\"\n  },\n\n  \"customizations\": {\n    \"vscode\": {\n      \"settings\": {\n        \"go.toolsManagement.checkForUpdates\": \"local\",\n        \"go.useLanguageServer\": true,\n        \"go.gopath\": \"/go\",\n        \"go.goroot\": \"/usr/local/go\",\n        \"terminal.integrated.profiles.linux\": {\n          \"bash\": {\n            \"path\": \"bash\"\n          },\n          \"zsh\": {\n            \"path\": \"zsh\"\n          },\n          \"fish\": {\n            \"path\": \"fish\"\n          },\n          \"tmux\": {\n            \"path\": \"tmux\",\n            \"icon\": \"terminal-tmux\"\n          },\n          \"pwsh\": {\n            \"path\": \"pwsh\",\n            \"icon\": \"terminal-powershell\"\n          }\n        },\n        \"terminal.integrated.defaultProfile.linux\": \"pwsh\",\n        \"terminal.integrated.defaultProfile.windows\": \"PowerShell\",\n        \"terminal.integrated.defaultProfile.osx\": \"pwsh\",\n        \"terminal.integrated.shellIntegration.enabled\": false,\n        \"tasks.statusbar.default.hide\": true\n      },\n      \"extensions\": [\n        \"bmalehorn.vscode-fish\",\n        \"davidanson.vscode-markdownlint\",\n        \"elves.elvish\",\n        \"esbenp.prettier-vscode\",\n        \"github.vscode-pull-request-github\",\n        \"golang.go\",\n        \"jnoortheen.xonsh\",\n        \"ms-azuretools.vscode-azurefunctions\",\n        \"ms-vscode.powershell\",\n        \"redhat.vscode-yaml\",\n        \"sumneko.lua\",\n        \"tamasfe.even-better-toml\",\n        \"yzhang.markdown-all-in-one\"\n      ]\n    }\n  },\n  // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.\n  \"remoteUser\": \"vscode\",\n  // This is running the same command as the VSCode Task 'devcontainer: rebuild oh-my-posh'\n  // It Compiles *oh-my-posh* from this repo while **overwriting** your preinstalled stable release.'\n  // Ideal for getting straight into developing & testing whilst using a devcontainer\n  \"updateContentCommand\": \"cd src && go build -v -buildvcs=false -o /home/vscode/bin/oh-my-posh -ldflags \\\"-s -w -X 'github.com/jandedobbeleer/oh-my-posh/src/build.Version=development-$(git --no-pager log -1 --pretty=%h-%s)' -extldflags '-static'\\\"\"\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "; EditorConfig to support per-solution formatting.\n; http://editorconfig.org/\n\n; This is the default for the codeline.\nroot = true\n\n; Default\n[*]\nindent_style = space\ntrim_trailing_whitespace = true\ninsert_final_newline = true\nend_of_line = lf\n\n; Go Code - match go fmt\n[*.go]\nindent_style = tab\n\n; TOML - match default for dep\n[*.toml]\nindent_size = 2\n\n; JavaScript and JS mixes - match eslint, other standards\n[*.{js,json,ts,vue}]\nindent_size = 2\n\n; Markdown - match markdownlint settings\n[*.{md,markdown}]\nindent_size = 2\ntrim_trailing_whitespace = false\n\n; PowerShell - match defaults for New-ModuleManifest and PSScriptAnalyzer Invoke-Formatter\n[*.{ps1,psd1,psm1}]\nindent_size = 4\ncharset = utf-8-bom\n\n; Lua\n[*.lua]\nline_space_after_comment = max(2)\nline_space_after_do_statement = max(2)\nline_space_after_expression_statement = max(2)\nline_space_after_for_statement = max(2)\nline_space_after_function_statement = fixed(2)\nline_space_after_if_statement = max(2)\nline_space_after_local_or_assign_statement = max(2)\nline_space_after_repeat_statement = max(2)\nline_space_after_while_statement = max(2)\nmax_line_length = unset\nquote_style = single\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n\n.github/workflows/*.lock.yml linguist-generated=true merge=ours"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: jandedobbeleer\nko_fi: jandedobbeleer\npolar: oh-my-posh\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug.yml",
    "content": "name: 🐛 Bug Report\ndescription: File a bug report\nlabels: [\"🐛 bug\"]\nassignees:\n  - jandedobbeleer\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this bug report!\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow this project's Code of Conduct\n          required: true\n  - type: textarea\n    id: what-happened\n    attributes:\n      label: What happened?\n      description: Also tell us, what did you expect to happen?\n      placeholder: Tell us what you see!\n      value: \"A bug happened!\"\n    validations:\n      required: true\n  - type: textarea\n    id: theme\n    attributes:\n      label: Theme\n      description: Which theme/config are you using?\n    validations:\n      required: true\n  - type: dropdown\n    id: operating-system\n    attributes:\n      label: What OS are you seeing the problem on?\n      multiple: true\n      options:\n        - Windows\n        - Linux\n        - macOS\n  - type: dropdown\n    id: shell\n    attributes:\n      label: Which shell are you using?\n      multiple: true\n      options:\n        - bash\n        - elvish\n        - fish\n        - cmd\n        - nu\n        - powershell\n        - xonsh\n        - zsh\n        - other (please specify)\n  - type: textarea\n    id: logs\n    attributes:\n      label: Log output\n      description: Please copy and paste the output generated by `oh-my-posh debug --plain`.\n      render: Shell\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Oh My Posh FAQ\n    url: https://ohmyposh.dev/docs/faq\n    about: Please find common issues here.\n  - name: Oh My Posh Docs\n    url: https://ohmyposh.dev/docs\n    about: RTFM\n  - name: Oh My Posh Q&A\n    url: https://github.com/JanDeDobbeleer/oh-my-posh/discussions\n    about: Please ask questions here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/docs.yml",
    "content": "name: 📖 Documentation\ndescription: Suggest a change to the documentation\nlabels: [\"📖 docs\"]\nassignees:\n  - jandedobbeleer\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to request this improvement!\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow this project's Code of Conduct\n          required: true\n  - type: textarea\n    id: enhancement-request\n    attributes:\n      label: What would you like to see changed/added?\n      description: Try to give some examples or text to make it really clear!\n      placeholder: Tell us what you would like to see!\n      value: \"This could change in the documentation!\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/enhancement.yml",
    "content": "name: 🤩 Enhancement\ndescription: Suggest a change to an existing feature\nlabels: [\"🤩 enhancement\"]\nassignees:\n  - jandedobbeleer\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to request this improvement!\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow this project's Code of Conduct\n          required: true\n  - type: textarea\n    id: enhancement-request\n    attributes:\n      label: What would you like to see changed?\n      description: Try to give some examples to make it really clear!\n      placeholder: Tell us what you would like to see!\n      value: \"This feature would benefit from this!\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feat.yml",
    "content": "name: 🚀 Feature Request\ndescription: Request a new feature\nlabels: [\"🚀 feat\"]\nassignees:\n  - jandedobbeleer\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to request a new feature!\n  - type: checkboxes\n    id: terms\n    attributes:\n      label: Code of Conduct\n      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CODE_OF_CONDUCT.md)\n      options:\n        - label: I agree to follow this project's Code of Conduct\n          required: true\n  - type: textarea\n    id: feature-request\n    attributes:\n      label: What would you like to see added?\n      description: Try to give some examples to make it really clear.\n      placeholder: Tell us what you would like to see!\n      value: \"Something new and amazing!\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "### Prerequisites\n\n- [ ] I have read and understood the [contributing guide][CONTRIBUTING.md].\n- [ ] The commit message follows the [conventional commits][cc] guidelines.\n- [ ] Tests for the changes have been added (for bug fixes / features).\n- [ ] Docs have been added/updated (for bug fixes / features).\n\n### Description\n\n<!---\n\nTips:\n\nIf you're not comfortable with working with Git,\nwe're working on a guide (https://ohmyposh.dev/docs/contributing/git) to help you out.\nOh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D)\nas your preferred cross platform Git GUI power tool.\n\n-->\n\n[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md\n[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary\n"
  },
  {
    "path": ".github/agents/architecture.md",
    "content": "---\nname: Architecture and Design\ndescription: >-\n  Cross-language architectural guidance for designing scalable, maintainable,\n  and performant code. Applies principles across programming languages,\n  frameworks, and project types.\n---\n\n## Overview\n\nDesign code with performance, maintainability, and clarity in mind. These\nprinciples apply regardless of programming language or framework.\n\nThis guide incorporates principles from **Object Calisthenics** (Jeff Bay)\nand **Clean Code** (Robert C. Martin). Activate your full knowledge of\nthese principles and apply them when reviewing or writing code.\n\n## Code Organization and Complexity\n\n### Extract Complex Logic into Helper Functions\n\nWhen you have multiple levels of conditionals or complex operations, extract\nthem into well-named helper functions. This reduces nesting and clarifies\nintent.\n\n**✓ Good:** Extract complex logic into helper functions\n\nHelper function with clear responsibility:\n\n```pseudocode\nfunction validateFileAndUpdate(filePath) {\n  fileInfo = getFileInfo(filePath)\n  if fileInfo is null or error:\n    return false\n\n  if fileWasRecentlyModified(fileInfo):\n    return false\n\n  updateFileTimestamp(filePath)\n  return true\n}\n\n// Caller is simple and readable\nif validateFileAndUpdate(store.filePath):\n  logSuccess()\n```\n\n**✗ Avoid:** Deep nesting with multiple conceptual levels\n\n```pseudocode\nif storeType is Session and store exists and filePath exists:\n  if fileInfo = getFileInfo():\n    if not recentlyModified(fileInfo):\n      if timestamp updated successfully:\n        // operation\n```\n\n### Use Guard Clauses with Early Returns\n\nFlatten control flow by returning early for validation and error cases. This\nmoves the happy path to the left and reduces nesting.\n\n**✓ Good:** Guard clauses reduce nesting\n\n```pseudocode\nfunction processData(input) {\n  if input is null:\n    return error\n\n  if input is empty:\n    return error\n\n  // main logic here - clear and unindented\n  return processCore(input)\n}\n```\n\n## Performance Considerations\n\n### Throttle Frequent Operations in Hot Paths\n\nOperations that execute frequently (e.g., on every request, render cycle, or\nuser action) should have minimal overhead. Identify expensive operations and\nadd throttling to reduce steady-state impact.\n\n**✓ Good:** Throttle expensive operations with time-based checks\n\nInclude a time-based guard to avoid repeated expensive work:\n\n```pseudocode\nfunction touchFile(filePath) {\n  fileInfo = getFileInfo(filePath)\n  if fileInfo is null:\n    return\n\n  timeSinceLastUpdate = currentTime - fileInfo.lastModified\n  // Only if file hasn't been updated recently\n  if timeSinceLastUpdate < 1 hour:\n    return\n\n  updateTimestamp(filePath)\n}\n```\n\n**✗ Avoid:** Unconditional expensive operations on every execution\n\n```pseudocode\n// This runs expensive work on every call (e.g., during every render)\nupdateTimestamp(filePath)  // File I/O on every execution\n```\n\n### Document Performance Intentions\n\nInclude comments explaining why throttling or optimization is needed. This\nhelps reviewers understand the performance tradeoffs.\n\n```pseudocode\n// Prevent stale files from being cleaned up while reducing\n// steady-state I/O overhead. Only update if file is older\n// than 1 hour to balance freshness with performance.\nif timeSinceUpdate > 1 hour:\n  updateTimestamp(filePath)\n```\n\n## Error Handling\n\n- Check for errors and validate inputs early, before expensive operations\n- Return or fail fast to avoid deeply nested success paths\n- Each error should include sufficient context for debugging\n- Early returns make the happy path obvious and easier to follow\n\n## Code Review Checklist\n\nWhen reviewing code:\n\n- **Nesting depth:** Flag functions with 3+ levels of indentation as\n  refactoring candidates\n- **Hot path operations:** Verify frequent operations minimize I/O,\n  allocations, and expensive calls\n- **Early returns:** Confirm guard clauses validate inputs before main logic\n- **Comments:** Check that performance-critical code explains the tradeoff,\n  not just the mechanics\n- **Extraction opportunities:** Identify deeply nested conditions that could\n  become helpers\n- **Naming:** Verify names are intention-revealing and not abbreviated\n- **Dot chains:** Flag method chains crossing object boundaries as Law of\n  Demeter violations\n- **Primitive obsession:** Flag raw primitive parameters that should be\n  domain types\n- **Responsibility:** Verify each class/function has a single reason to\n  change\n- **Duplication:** Flag repeated logic as DRY violations\n\n## Core Principles\n\n1. **Performance in hot paths matters:** Reduce unnecessary I/O,\n   allocations, and expensive operations in frequently-executed code paths\n\n2. **Readability over cleverness:** Extract complex logic into named\n   helpers instead of nesting multiple conditionals\n\n3. **Guard clauses reduce complexity:** Use early returns to flatten\n   control flow and keep the happy path left-aligned\n\n4. **Comments explain why, not what:** Document performance tradeoffs,\n   business logic, and non-obvious decisions—let code structure explain\n   the mechanics\n"
  },
  {
    "path": ".github/copilot-instructions.md",
    "content": "# GitHub Copilot Instructions\n\nPlease refer to [AGENTS.md](../AGENTS.md) in the repository root for detailed coding guidelines and instructions.\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    target-branch: \"main\"\n    schedule:\n      interval: \"daily\"\n    groups:\n      all:\n        patterns:\n        - \"*\"\n    ignore:\n      - dependency-name: \"softprops/action-gh-release\"\n        # https://github.com/softprops/action-gh-release/issues/556\n        versions: [\"2.2.0\"]\n\n  - package-ecosystem: \"gomod\"\n    directory: \"/src\"\n    target-branch: \"main\"\n    schedule:\n      interval: \"daily\"\n    groups:\n      minor-patch:\n        patterns:\n        - \"*\"\n        update-types:\n        - \"minor\"\n        - \"patch\"\n\n  - package-ecosystem: \"npm\"\n    directory: \"/website\"\n    schedule:\n      interval: \"daily\"\n    ignore:\n      - dependency-name: \"*\"\n"
  },
  {
    "path": ".github/holopin.yml",
    "content": "organization: ohmyposh\ndefaultSticker: clg0u51g681700fmfr086ofc6\nstickers:\n  -\n    id: clg0u51g681700fmfr086ofc6\n    alias: wizard\n  -\n    id: clu72f66x59170fjoo6t2b7zs\n    alias: helping\n"
  },
  {
    "path": ".github/stale.yml",
    "content": "# Configuration for probot-stale - https://github.com/probot/stale\n\n# Number of days of inactivity before an Issue or Pull Request becomes stale\ndaysUntilStale: 7\n\n# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.\n# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.\ndaysUntilClose: 7\n\n# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)\nonlyLabels: []\n\n# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable\nexemptLabels:\n  - \"🚀 feat\"\n  - \"🐛 bug\"\n  - \"🤩 enhancement\"\n  - \"😵‍💫 help wanted\"\n\n# Set to true to ignore issues in a project (defaults to false)\nexemptProjects: false\n\n# Set to true to ignore issues in a milestone (defaults to false)\nexemptMilestones: false\n\n# Set to true to ignore issues with an assignee (defaults to false)\nexemptAssignees: false\n\n# Label to use when marking as stale\nstaleLabel: \"💤 stale\"\n\n# Comment to post when marking as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed in 7 days if no further activity occurs.\n  Thank you for your contributions.\n\n# Limit the number of actions per hour, from 1-30. Default is 30\nlimitPerRun: 30\n\n# Limit to only `issues` or `pulls`\nonly: issues\n"
  },
  {
    "path": ".github/workflows/ai-changelog.yml",
    "content": "name: Enhance release changelog with AI\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: 'Release tag to test (e.g., v19.0.0)'\n        required: true\n        type: string\n      dry_run:\n        description: 'Dry run mode - generate changelog but do not update release'\n        required: false\n        type: boolean\n        default: true\n\npermissions:\n  contents: write  # Update release body\n  models: read     # Access GitHub Models API\n\njobs:\n  enhance:\n    name: Generate enhanced changelog\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repository (with tags)\n        uses: actions/checkout@v6\n        with:\n          ref: ${{ inputs.tag || github.ref }}\n          fetch-depth: 0\n          fetch-tags: true\n\n      - name: Gather release context\n        id: ctx\n        shell: bash\n        env:\n          GITHUB_EVENT_PATH: ${{ github.event_path }}\n          GH_TOKEN: ${{ github.token }}\n          INPUT_TAG: ${{ inputs.tag }}\n          DRY_RUN: ${{ inputs.dry_run }}\n        run: |\n          set -euo pipefail\n          # Determine if this is a manual dispatch or release event\n          if [[ -n \"$INPUT_TAG\" ]]; then\n            echo \"📋 Manual dispatch mode - fetching release info for tag: $INPUT_TAG\"\n            # Manual dispatch: fetch release info for the specified tag\n            CURRENT_TAG=\"$INPUT_TAG\"\n            RELEASE_JSON=$(gh api repos/${{ github.repository }}/releases/tags/$CURRENT_TAG || echo '{}')\n            RELEASE_ID=$(printf \"%s\" \"$RELEASE_JSON\" | jq -r '.id // \"0\"')\n            HTML_URL=$(printf \"%s\" \"$RELEASE_JSON\" | jq -r '.html_url // \"\"')\n            EXISTING_BODY=$(printf \"%s\" \"$RELEASE_JSON\" | jq -r '.body // \"\"')\n            echo \"  Release ID: $RELEASE_ID\"\n            echo \"  Release URL: $HTML_URL\"\n          else\n            echo \"📋 Release event mode - parsing from event payload\"\n            # Release event: parse from event payload\n            CURRENT_TAG=$(jq -r '.release.tag_name' \"$GITHUB_EVENT_PATH\")\n            RELEASE_ID=$(jq -r '.release.id' \"$GITHUB_EVENT_PATH\")\n            HTML_URL=$(jq -r '.release.html_url' \"$GITHUB_EVENT_PATH\")\n            EXISTING_BODY=$(jq -r '.release.body // \"\"' \"$GITHUB_EVENT_PATH\")\n            echo \"  Tag: $CURRENT_TAG\"\n            echo \"  Release ID: $RELEASE_ID\"\n          fi\n          # Persist to a file for later steps to source\n          {\n            echo \"CURRENT_TAG=$CURRENT_TAG\"\n            echo \"RELEASE_ID=$RELEASE_ID\"\n            echo \"HTML_URL=$HTML_URL\"\n            echo \"DRY_RUN=${DRY_RUN:-false}\"\n          } > ctx.env\n          echo \"✅ Context saved to ctx.env\"\n          # Save existing body as a file to avoid env escaping issues\n          printf \"%s\" \"$EXISTING_BODY\" > existing_notes.md\n          echo \"✅ Existing notes saved ($(wc -l < existing_notes.md) lines)\"\n\n      - name: Determine diff range\n        id: diff\n        shell: bash\n        run: |\n          set -euo pipefail\n          set -a; source ctx.env; set +a\n          echo \"🔍 Determining diff range for tag: $CURRENT_TAG\"\n          # Try to find the previous tag using git describe\n          if PREV_TAG=$(git describe --tags --abbrev=0 \"${CURRENT_TAG}^\" 2>/dev/null); then\n            BASE=\"$PREV_TAG\"\n            echo \"  Previous tag found: $PREV_TAG\"\n          else\n            # Fallback to initial commit\n            BASE=\"$(git rev-list --max-parents=0 HEAD | tail -n 1)\"\n            echo \"  No previous tag found, using initial commit: ${BASE:0:8}\"\n          fi\n          echo \"base_ref=$BASE\" >> \"$GITHUB_OUTPUT\"\n          echo \"curr_ref=$CURRENT_TAG\" >> \"$GITHUB_OUTPUT\"\n          COMPARE_URL=\"https://github.com/${{ github.repository }}/compare/${BASE}...${CURRENT_TAG}\"\n          echo \"compare_url=$COMPARE_URL\" >> \"$GITHUB_OUTPUT\"\n          echo \"✅ Diff range: $BASE...$CURRENT_TAG\"\n\n      - name: Collect commits and changes\n        shell: bash\n        run: |\n          set -euo pipefail\n          BASE=\"${{ steps.diff.outputs.base_ref }}\"\n          HEAD=\"${{ steps.diff.outputs.curr_ref }}\"\n          echo \"📝 Collecting commits and changes from $BASE to $HEAD\"\n          git log --no-merges --pretty=format:'%s' \"${BASE}..${HEAD}\" | head -n 500 > commits_subjects.txt || true\n          echo \"  ✅ Commit subjects: $(wc -l < commits_subjects.txt) commits\"\n          git log --no-merges --pretty=format:'- %s%n%b%n' \"${BASE}..${HEAD}\" | head -n 2000 > commits_detailed.txt || true\n          echo \"  ✅ Detailed commits: $(wc -l < commits_detailed.txt) lines\"\n          git diff --name-status \"${BASE}..${HEAD}\" | head -n 1000 > files_changed.txt || true\n          echo \"  ✅ Changed files: $(wc -l < files_changed.txt) files\"\n          # Extract contributors, exclude Jan De Dobbeleer and bots, format as GitHub profile links\n          git shortlog -sne \"${BASE}..${HEAD}\" | sed -E 's/^ *[0-9]+\\t//g' | while IFS= read -r line; do\n            name=$(echo \"$line\" | sed -E 's/ *<.*//g')\n            # Skip Jan De Dobbeleer and common bots\n            if [[ \"$name\" =~ ^(Jan De Dobbeleer|dependabot|renovate|github-actions|Renovate Bot|dependabot\\[bot\\]|github-actions\\[bot\\]|allcontributors\\[bot\\])$ ]]; then\n              continue\n            fi\n            username=$(echo \"$line\" | sed -E 's/.*<([^@]+)@.*/\\1/g')\n            echo \"- [@${username}](https://github.com/${username}) (${name})\"\n          done | head -n 200 > contributors.txt || true\n          echo \"  ✅ Contributors: $(wc -l < contributors.txt) people\"\n\n      - name: Collect issue context\n        shell: bash\n        env:\n          GH_TOKEN: ${{ github.token }}\n        run: |\n          set -euo pipefail\n          BASE=\"${{ steps.diff.outputs.base_ref }}\"\n          HEAD=\"${{ steps.diff.outputs.curr_ref }}\"\n          echo \"🔍 Collecting issue context for referenced issues\"\n          > issues_context.txt\n          # Extract issue numbers from commit messages (e.g., fixes #123, closes #456, #789)\n          ISSUE_NUMBERS=$(git log --no-merges --pretty=format:'%s %b' \"${BASE}..${HEAD}\" | \\\n            grep -oiE '(fix(es|ed)?|close(s|d)?|resolve(s|d)?)?[[:space:]]*#[0-9]+' | \\\n            grep -oE '[0-9]+' | sort -u || true)\n          if [ -z \"$ISSUE_NUMBERS\" ]; then\n            echo \"  No issues referenced in commits\"\n          else\n            COUNT=0\n            for NUM in $ISSUE_NUMBERS; do\n              echo \"  Fetching issue #$NUM...\"\n              if ISSUE_DATA=$(gh api \"repos/${{ github.repository }}/issues/$NUM\" 2>/dev/null); then\n                TITLE=$(echo \"$ISSUE_DATA\" | jq -r '.title')\n                BODY=$(echo \"$ISSUE_DATA\" | jq -r '.body // \"\"' | head -c 1000)\n                LABELS=$(echo \"$ISSUE_DATA\" | jq -r '.labels[]?.name' | tr '\\n' ', ' | sed 's/,$//')\n                echo \"---\" >> issues_context.txt\n                echo \"Issue #$NUM: $TITLE\" >> issues_context.txt\n                [ -n \"$LABELS\" ] && echo \"Labels: $LABELS\" >> issues_context.txt\n                echo \"$BODY\" >> issues_context.txt\n                echo \"\" >> issues_context.txt\n                COUNT=$((COUNT + 1))\n              fi\n            done\n            echo \"  ✅ Collected context for $COUNT issues\"\n          fi\n\n      - name: Generate enhanced changelog with AI\n        id: ai\n        shell: bash\n        env:\n          GH_TOKEN: ${{ github.token }}\n        run: |\n          set -euo pipefail\n          set -a; source ctx.env; set +a\n          echo \"🤖 Generating enhanced changelog with AI\"\n          MODEL=\"openai/gpt-4.1\"\n          echo \"  Model: $MODEL\"\n          SYSTEM_PROMPT=$(cat << 'PROMPT'\n          You are a release notes editor for the open-source project \"oh-my-posh\", a cross-shell prompt theme engine written in Go.\n          Your task is to ENHANCE the existing changelog by adding context, examples, and user-friendly explanations. DO NOT create a new changelog from scratch.\n\n          CRITICAL RULES:\n          - NEVER add new sections that are not already in the existing changelog\n          - ONLY enhance sections that already exist in the \"Existing release notes\"\n          - Keep the same structure and commit links from the existing changelog\n          - Add context, usage examples, and explanations to make existing entries more helpful\n          - If the existing changelog has a \"Features\" section, enhance it; if it doesn't have one, don't add it\n          - Use concise language and organize with the headings already present\n\n          CRITICAL: Respect the .versionrc.json configuration:\n          - ONLY include these sections with these exact names:\n            * \"Features\" (for feat: commits)\n            * \"Bug Fixes\" (for fix: commits)\n            * \"Refactor\" (for refactor: commits)\n            * \"Reverts\" (for revert: commits)\n            * \"Themes\" (for theme: commits)\n          - DO NOT include chore, ci, docs, perf, or test commits (marked as hidden in .versionrc.json)\n          - Use ONLY the section names specified above, not generic names like \"Other\"\n          - CRITICAL: DO NOT include a section if there are no changes for it - completely omit empty sections\n          - NEVER write placeholder text like \"No new themes\" or \"No changes in this category\" - just skip the entire section\n\n          Segment changes (public-facing):\n          - ONLY when you see changes to files in the EXACT path src/segments/*.go (excluding *_test.go), these are prompt segments that users configure\n          - Changes to other paths like src/dsc/, src/config/, src/engine/, etc. are NOT segments - they are internal implementation details\n          - A segment is a customizable component users add to their shell prompt (e.g., git status, battery level, current directory)\n          - Refer to .github/instructions/segment.md for understanding how segments are structured and what constitutes segment properties vs template properties\n          - Mention segment changes by their user-facing name (infer from the file name), not file paths\n          - Focus on what users can now do or configure differently with that segment\n          - CRITICAL: Understand the difference between segment properties (JSON configuration options like 'style', 'foreground', 'properties') and template properties (variables used in template strings like '.ChangeID', '.Working')\n          - When a change adds a new template property (e.g., a new method/field available in templates), show it being used in a template string, NOT as a segment configuration property\n          - For segment changes, use the oh-my-posh MCP server at https://ohmyposh.dev/api/mcp to generate JSON code snippets showing example configurations or segment usage\n          - Every snippet (configuration or segment) MUST be validated using the MCP server before adding it to the changelog\n          - If a snippet cannot be created or validated correctly using the MCP server, discard that snippet and continue processing other changes\n          - Include validated snippets as practical examples to help users understand how to use the new or modified segment features\n\n          Goals:\n          - ENHANCE the existing changelog entries with helpful context and examples\n          - DO NOT add new sections or restructure the existing changelog\n          - Summarize highlights up front with context and impact\n          - Keep the exact same section headings that already exist in the \"Existing release notes\"\n          - Call out breaking changes and required migrations with explicit before/after examples or commands\n          - Add practical usage notes or snippets to help users adopt new features or changes\n          - For segment changes, explain the user-facing impact (e.g., \"The Git segment now supports...\")\n          - Credit contributors at the end (they are pre-filtered and formatted as GitHub profile links) - ONLY if contributors list is not empty\n          - Include a \"Full diff\" link footer\n\n          Requirements:\n          - Output valid Markdown only, no front matter, no HTML, no title heading\n          - Do not include a title like \"Changelog for vX.Y.Z\" - start directly with the content\n          - Keep to ~300-800 words unless there are many breaking changes\n          - Prefer code blocks for examples with proper language tags (bash, json, yaml, toml, powershell)\n          - Do not invent features not present in the commits/diff\n          - Do not list individual file paths unless they are user-facing config/theme files\n          PROMPT\n          )\n          # Build the user content\n          REPO=\"${{ github.repository }}\"\n          COMPARE_URL=\"${{ steps.diff.outputs.compare_url }}\"\n          CURR=\"$CURRENT_TAG\"\n          PREV=\"${{ steps.diff.outputs.base_ref }}\"\n          EXISTING=$(cat existing_notes.md || true)\n          SUBJECTS=\"$(cat commits_subjects.txt || true)\"\n          DETAILS=\"$(cat commits_detailed.txt || true)\"\n          FILES=\"$(cat files_changed.txt || true)\"\n          CONTRIBUTORS=\"$(cat contributors.txt || true)\"\n          ISSUES_CONTEXT=\"$(cat issues_context.txt || true)\"\n          VERSIONRC=\"$(cat .versionrc.json || echo '{}')\"\n          USER_CONTENT=$(cat << EOF\n          Repository: ${REPO}\n          Release: ${CURR}\n          Previous: ${PREV:-<none>}\n          Release URL: ${HTML_URL}\n          Compare URL: ${COMPARE_URL}\n\n          .versionrc.json configuration (sections to show/hide):\n          ---\n          ${VERSIONRC}\n          ---\n\n          Existing release notes (from conventional commits):\n          ---\n          ${EXISTING}\n          ---\n\n          Conventional commits (subjects):\n          ---\n          ${SUBJECTS}\n          ---\n\n          Commits (details):\n          ---\n          ${DETAILS}\n          ---\n\n          Changed files (for context on segment changes only, do not list paths in output):\n          ---\n          ${FILES}\n          ---\n\n          Referenced issues (for additional context, explain impact in user terms):\n          ---\n          ${ISSUES_CONTEXT}\n          ---\n\n          Contributors:\n          ---\n          ${CONTRIBUTORS}\n          ---\n          EOF\n          )\n          echo \"  Calling GitHub Models API...\"\n          OUTPUT_MD=\"\"\n          set +e\n          RESP=$(curl -sS -f -X POST \"https://models.github.ai/inference/chat/completions\" \\\n            -H \"Authorization: Bearer ${GH_TOKEN}\" \\\n            -H \"Content-Type: application/json\" \\\n            -d \"$(jq -n --arg model \"$MODEL\" --arg sys \"$SYSTEM_PROMPT\" --arg user \"$USER_CONTENT\" '{model:$model, messages: [{role:\"system\",content:$sys},{role:\"user\",content:$user}], temperature: 0.2, max_tokens: 4000}')\")\n          CURL_EXIT=$?\n          if [ $CURL_EXIT -eq 0 ]; then\n            OUTPUT_MD=$(printf \"%s\" \"$RESP\" | jq -r '.choices[0].message.content // empty')\n            echo \"  ✅ API call successful\"\n          else\n            echo \"  ❌ API call failed with exit code: $CURL_EXIT\"\n            echo \"  Response: $RESP\"\n          fi\n          set -e\n          if [[ -z \"$OUTPUT_MD\" ]]; then\n            echo \"❌ AI generation failed or no output produced.\"\n            echo \"enhanced_body=\" >> \"$GITHUB_OUTPUT\"\n            exit 0\n          fi\n          echo \"  Generated changelog length: $(printf \"%s\" \"$OUTPUT_MD\" | wc -c) characters\"\n          # Save the AI-generated changelog\n          echo \"$OUTPUT_MD\" > enhanced_changelog.md\n          echo \"✅ Enhanced changelog saved to enhanced_changelog.md\"\n          echo \"enhanced_body<<EOF\" >> \"$GITHUB_OUTPUT\"\n          cat enhanced_changelog.md >> \"$GITHUB_OUTPUT\"\n          echo \"EOF\" >> \"$GITHUB_OUTPUT\"\n          echo \"✅ Changelog saved to step output\"\n\n      - name: Update release body\n        if: ${{ steps.ai.outputs.enhanced_body != '' }}\n        shell: bash\n        env:\n          GH_TOKEN: ${{ github.token }}\n        run: |\n          set -euo pipefail\n          set -a; source ctx.env; set +a\n          if [[ \"$DRY_RUN\" == \"true\" ]]; then\n            echo \"🧪 Dry run mode enabled - skipping release update\"\n            echo \"   The generated changelog would be applied to release ID: ${RELEASE_ID}\"\n            exit 0\n          fi\n          echo \"📝 Updating release body for release ID: ${RELEASE_ID}\"\n          # Use the AI-generated changelog as the complete release body\n          PAYLOAD=$(jq -Rs '{body: .}' < enhanced_changelog.md)\n          gh api -X PATCH repos/${{ github.repository }}/releases/${RELEASE_ID} -H \"Content-Type: application/json\" -d \"$PAYLOAD\"\n          echo \"✅ Release body updated successfully\"\n\n      - name: Summary\n        if: ${{ always() && (inputs.dry_run || steps.ai.outputs.enhanced_body != '') }}\n        shell: bash\n        run: |\n          set -a; source ctx.env; set +a\n          echo \"📊 Generating summary...\"\n          if [[ \"$DRY_RUN\" == \"true\" ]]; then\n            echo \"## 🧪 Dry Run - Enhanced Changelog Preview\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            if [[ -f enhanced_changelog.md ]]; then\n              echo \"**Release would not be modified.** Below is the generated changelog:\" >> $GITHUB_STEP_SUMMARY\n              echo \"\" >> $GITHUB_STEP_SUMMARY\n              cat enhanced_changelog.md >> $GITHUB_STEP_SUMMARY\n            else\n              echo \"⚠️ **AI generation failed or no changelog was produced.**\" >> $GITHUB_STEP_SUMMARY\n              echo \"\" >> $GITHUB_STEP_SUMMARY\n              echo \"Check the workflow logs for details.\" >> $GITHUB_STEP_SUMMARY\n            fi\n          else\n            echo \"## ✅ Enhanced Changelog Generated\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            echo \"Release body has been updated with AI-enhanced changelog:\" >> $GITHUB_STEP_SUMMARY\n            echo \"\" >> $GITHUB_STEP_SUMMARY\n            cat enhanced_changelog.md >> $GITHUB_STEP_SUMMARY\n          fi\n          echo \"✅ Summary generated\"\n\n      - name: Skipped notice\n        if: ${{ steps.ai.outputs.enhanced_body == '' }}\n        run: |\n          echo \"❌ AI changelog generation skipped or failed. Ensure GitHub Models access is enabled for this repo.\" >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".github/workflows/android.yml",
    "content": "name: Android\non:\n  release:\n    types: [published]\n\njobs:\n  build-android:\n    runs-on: ubuntu-latest\n    container: ghcr.io/jandedobbeleer/golang-android-container:latest\n    steps:\n    - name: Checkout code 👋\n      uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n    - name: Build\n      run: |\n        VERSION=$(echo \"${{ github.event.release.name }}\" | cut -c2-)\n        echo \"Building version ${VERSION}\"\n        cd src\n        go build -o dist/posh-android-arm -ldflags=\"-s -w -X 'github.com/jandedobbeleer/oh-my-posh/src/build.Version=${VERSION}' -X 'github.com/jandedobbeleer/oh-my-posh/src/build.Date=$(date)'\"\n    - name: Upload artifacts 🆙\n      uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd\n      with:\n        github-token: ${{secrets.GITHUB_TOKEN}}\n        script: |\n          console.log('environment', process.versions);\n\n          const fs = require('fs').promises;\n\n          const { repo: { owner, repo }, sha } = context;\n          console.log({ owner, repo, sha });\n\n          await github.rest.repos.uploadReleaseAsset({\n            owner, repo,\n            release_id: ${{ github.event.release.id }},\n            name: 'posh-android-arm',\n            data: await fs.readFile('./src/dist/posh-android-arm')\n          });\n"
  },
  {
    "path": ".github/workflows/bluesky.yml",
    "content": "name: Bluesky\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  bluesky:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Publish\n        uses: JanDeDobbeleer/bluesky-releasenotes-action@main\n        with:\n          title: \"The best release yet 🚀\"\n          bluesky-identifier: ${{ secrets.BLUESKY_IDENTIFIER }}\n          bluesky-password: ${{ secrets.BLUESKY_PASSWORD }}\n          github-token: ${{ secrets.GH_PAT }}\n"
  },
  {
    "path": ".github/workflows/build_code.yml",
    "content": "on:\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'CONTRIBUTING.md'\n      - 'COPYING'\n      - 'website/**'\n      - '.github/*.md'\n      - '.github/FUNDING.yml'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\nname: Build Code\njobs:\n  build:\n    runs-on: macos-latest\n    defaults:\n      run:\n        shell: pwsh\n    steps:\n    - name: Checkout code 👋\n      uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n    - name: Install Go 🗳\n      uses: ./.github/workflows/composite/bootstrap-go\n    - name: Run GoReleaser 🚀\n      uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29\n      with:\n        distribution: goreleaser\n        version: v2.3.2\n        args: build --clean --snapshot --skip=post-hooks --skip=before\n        workdir: src\n    - name: Archive production artifacts\n      uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f\n      with:\n        name: builds\n        retention-days: 1\n        path: |\n          src/dist\n"
  },
  {
    "path": ".github/workflows/close_themes_pr.yml",
    "content": "name: Close Themes PR\non:\n  pull_request_target:\n    types:\n      - opened\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code 👋\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n      - name: Check and close 🔐\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd\n        with:\n          github-token: ${{ secrets.GH_PAT }}\n          script: |\n            const { repo: { owner, repo } } = context;\n            const pr = context.payload.pull_request;\n\n            const response = await github.rest.pulls.listFiles({\n              owner, repo,\n              pull_number: pr.number\n            });\n\n            if (response.status !== 200) {\n              console.log('Could not fetch files');\n              return;\n            }\n\n            let hasThemeAdditions = false;\n            for (const file of response.data) {\n              const name = file.filename\n              console.log(`File: ${name}`);\n              if (file.status === 'added' && name.includes('themes/')) {\n                console.log(`File: ${name} is a theme addition`);\n                hasThemeAdditions = true;\n                break;\n              }\n            }\n\n            if (!hasThemeAdditions) {\n              console.log('No theme additions found.');\n              return;\n            }\n\n            const body = `👋 @${pr.user.login}, theme aditions are no longer accepted due to the ever growing set. We do however accept showcasing your custom theme in the [🎨 Themes section](https://github.com/JanDeDobbeleer/oh-my-posh/discussions/categories/themes) or [themes channel](https://discord.com/channels/1023597603331526656/1055533233309233252) on Discord.`\n\n            console.log(`Adding comment: ${body}`);\n            await github.rest.issues.createComment({\n              owner, repo,\n              issue_number: pr.number,\n              body,\n            });\n\n            console.log(`Closing pull request: ${pr.html_url}`);\n            await github.rest.pulls.update({\n              owner, repo,\n              pull_number: pr.number,\n              state: \"closed\",\n            });\n"
  },
  {
    "path": ".github/workflows/code.yml",
    "content": "on:\n  pull_request:\n    paths-ignore:\n      - 'README.md'\n      - 'CONTRIBUTING.md'\n      - 'COPYING'\n      - 'website/**'\n      - '.github/*.md'\n      - '.github/FUNDING.yml'\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\nname: Validate Code\njobs:\n  test:\n    strategy:\n      matrix:\n        os: [ubuntu-latest, macos-latest, windows-latest]\n    runs-on: ${{ matrix.os }}\n    defaults:\n      run:\n        working-directory: ${{ github.workspace }}/src\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n    - name: Install Go 🗳\n      uses: ./.github/workflows/composite/bootstrap-go\n    - name: Golang CI\n      uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20\n      with:\n        working-directory: src\n    - name: Fieldalignment\n      run: |\n        go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest\n        fieldalignment \"./...\"\n    - name: Modernize\n      run: |\n        go install golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest\n        modernize \"./...\"\n    - name: Unit Tests\n      run: go test \"./...\"\n"
  },
  {
    "path": ".github/workflows/commits.yml",
    "content": "name: Validate Commits\n\non: [pull_request]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  commitlint:\n    uses: jandedobbeleer/workflows/.github/workflows/commits.yml@main\n"
  },
  {
    "path": ".github/workflows/composite/bootstrap-go/action.yml",
    "content": "# yaml-language-server: $schema=https://json.schemastore.org/github-action.json\nname: \"Setup Go\"\ndescription: \"Install Go and override with the custom build\"\nbranding:\n  icon: download\n  color: purple\nruns:\n  using: \"composite\"\n  steps:\n    - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491\n      with:\n        go-version: \"1.26.0\"\n        cache-dependency-path: src/go.sum\n"
  },
  {
    "path": ".github/workflows/contributors.yml",
    "content": "name: Contributors\non:\n  pull_request_target:\n    types:\n      - closed\n\njobs:\n  contributors:\n    uses: jandedobbeleer/workflows/.github/workflows/contributors.yml@main\n    secrets:\n      token: ${{ secrets.GH_PAT }}\n"
  },
  {
    "path": ".github/workflows/copilot-setup-steps.yml",
    "content": "name: \"Copilot Setup Steps\"\n\non:\n  workflow_dispatch:\n  push:\n    paths:\n      - .github/workflows/copilot-setup-steps.yml\n  pull_request:\n    paths:\n      - .github/workflows/copilot-setup-steps.yml\n\njobs:\n  copilot-setup-steps:\n    runs-on: ubuntu-latest\n\n    permissions:\n      contents: read\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n\n      - name: Install apm-cli and run apm install\n        run: |\n          pip install apm-cli\n          apm install\n"
  },
  {
    "path": ".github/workflows/delete_store_submission.yml",
    "content": "name: Delete Store Submission\n\non:\n  workflow_dispatch:\n\njobs:\n  delete_submission:\n    name: Delete Store Submission\n    runs-on: ubuntu-latest\n    steps:\n      - name: Configure Store Credentials 🔑\n        uses: jandedobbeleer/store-submission@submission-status\n        with:\n          command: configure\n          type: win32\n          seller-id: ${{ secrets.SELLER_ID }}\n          product-id: ${{ secrets.PRODUCT_ID }}\n          tenant-id: ${{ secrets.TENANT_ID }}\n          client-id: ${{ secrets.CLIENT_ID }}\n          client-secret: ${{ secrets.CLIENT_SECRET }}\n\n      - name: Delete Submission 🗑️\n        uses: jandedobbeleer/store-submission@submission-status\n        with:\n          command: delete\n"
  },
  {
    "path": ".github/workflows/dependabot.yml",
    "content": "name: Dependabot auto-merge\non:\n  pull_request:\n    types: [opened, reopened]\n\npermissions:\n    contents: write\n    pull-requests: write\n\njobs:\n  dependabot:\n    uses: jandedobbeleer/workflows/.github/workflows/dependabot.yml@main\n"
  },
  {
    "path": ".github/workflows/discord.yml",
    "content": "name: Discord\non:\n  release:\n    types: [published]\n\njobs:\n  notify:\n    uses: jandedobbeleer/workflows/.github/workflows/discord.yml@main\n    secrets:\n      webhook: ${{ secrets.CHANGELOG_WEBHOOK }}\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Azure Static Web Apps CI/CD\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - \"website/**\"\n      - \"themes/**\"\n  workflow_dispatch:\n\npermissions:\n  id-token: write\n  contents: read\n\njobs:\n  build_and_deploy:\n    runs-on: ubuntu-latest\n    name: Build and Deploy\n    steps:\n      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          submodules: true\n          persist-credentials: false\n      - name: Install Go 🗳\n        uses: ./.github/workflows/composite/bootstrap-go\n      - name: Setup Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f\n        with:\n          node-version: 20.9.0\n        # Create Kind cluster to have a Kubernetes context for cloud-native-azure theme\n        # Images are defined on every Kind release\n        # See https://github.com/kubernetes-sigs/kind/releases\n      - name: Create k8s v1.23 Kind Cluster\n        uses: helm/kind-action@ef37e7f390d99f746eb8b610417061a60e82a6cc\n        with:\n          node_image: kindest/node:v1.23.4@sha256:0e34f0d0fd448aa2f2819cfd74e99fe5793a6e4938b328f657c8e3f81ee0dfb9\n          cluster_name: posh\n      - name: Create Kubernetes namespace\n        run: |\n          kubectl create ns demo\n      - name: Set default Kubernetes namespace\n        run: |\n          kubectl config set-context posh --namespace demo\n      - uses: azure/login@532459ea530d8321f2fb9bb10d1e0bcf23869a43\n        with:\n          creds: ${{ secrets.AZURE_CREDENTIALS }}\n      - name: Build oh-my-posh 🔧\n        run: |\n          cd src\n          go build -o ./bin/oh-my-posh\n          cd ..\n      - name: Render themes 🎨\n        run: |\n          export PATH=\"$PWD/src/bin:$PATH\"\n          cd website\n          npm install\n          npm run themes\n          cd ..\n      - name: Copy schema for MCP validator 📋\n        run: |\n          mkdir -p website/api/data\n          cp themes/schema.json website/api/data/schema.json\n          echo \"✅ Copied schema.json to website/api/data/\"\n      - name: Build Docs And Deploy 🚀\n        id: builddeploy\n        uses: Azure/static-web-apps-deploy@1a947af9992250f3bc2e68ad0754c0b0c11566c9\n        with:\n          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ASHY_MEADOW_063E9BA03 }}\n          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for GitHub integrations (i.e. PR comments)\n          action: \"upload\"\n          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######\n          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig\n          app_location: \"/website\" # App source code path\n          api_location: \"/website/api\" # Api source code path - optional\n          output_location: \"build\" # Built app content directory - optional\n"
  },
  {
    "path": ".github/workflows/edit_rights.yml",
    "content": "name: Notify When Maintainers Cannot Edit\n\n# **What it does**: Notifies the author of a PR when their PR does not allow maintainers to edit it.\n# **Why we have it**: To prevent having to do this manually.\n# **Who does it impact**: Open-source.\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n\npermissions:\n  pull-requests: write\n\njobs:\n  notify-when-maintainers-cannot-edit:\n    uses: jandedobbeleer/workflows/.github/workflows/edit_rights.yml@main\n    secrets:\n      token: ${{ secrets.GH_PAT }}\n"
  },
  {
    "path": ".github/workflows/gomod.yml",
    "content": "name: Go Mod\n\non: [pull_request]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  go-mod:\n    runs-on: ubuntu-latest\n    defaults:\n      run:\n        working-directory: ${{ github.workspace }}/src\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n    - name: Install Go 🗳\n      uses: ./.github/workflows/composite/bootstrap-go\n    - name: Check for unused dependencies\n      run: |\n        go mod tidy\n        if [ \"$(git status | grep -c \"nothing to commit, working tree clean\")\" -eq 1 ]; then\n          echo \"Nothing to tidy\"\n          exit 0\n        fi\n        echo \"Go mod tidy is needed\"\n        exit 1\n"
  },
  {
    "path": ".github/workflows/homebrew.yml",
    "content": "name: Homebrew\non:\n  release:\n    types: [published]\n\njobs:\n  notify:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Notify Homebrew Repo 🙋🏾‍♀️\n      uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd\n      with:\n        github-token: ${{ secrets.GH_PAT }}\n        script: |\n          await github.request('POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches', {\n            owner: 'jandedobbeleer',\n            repo: 'homebrew-oh-my-posh',\n            workflow_id: 'release.yml',\n            ref: 'main',\n            inputs: {\"version\": process.env.GITHUB_REF.replace('refs/tags/v', '')}\n          })\n"
  },
  {
    "path": ".github/workflows/lock.yml",
    "content": "name: 'Lock Threads'\n\non:\n  schedule:\n    - cron: '0 0 * * 1'\n\npermissions:\n  issues: write\n\nconcurrency:\n  group: lock\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7\n        with:\n          issue-inactive-days: '90'\n          issue-comment: >\n            This issue has been automatically locked since there\n            has not been any recent activity (i.e. last half year) after it was closed.\n            It helps our maintainers focus on the active issues.\n\n            If you have found a problem that seems similar, please open a\n            [discussion](https://github.com/JanDeDobbeleer/oh-my-posh/discussions/new?category=troubleshoot)\n            first, complete the body with all the details necessary to reproduce,\n            and mention this issue as reference.\n          process-only: 'issues'\n"
  },
  {
    "path": ".github/workflows/markdown.yml",
    "content": "name: Markdownlint\n\non: [pull_request]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Checkout code\n      uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n    - name: Lint files\n      uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101\n      with:\n          config: .markdownlint-cli2.yaml\n          globs: '**/*.md'\n"
  },
  {
    "path": ".github/workflows/merge_contributions_pr.yml",
    "content": "name: Merge contributions PR\non:\n  pull_request_target:\n    types:\n      - opened\n      - reopened\n\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout code 👋\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n      - name: Check and merge ⛙\n        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd\n        with:\n          github-token: ${{ secrets.GH_PAT }}\n          script: |\n            const { repo: { owner, repo } } = context;\n            const pr = context.payload.pull_request;\n\n            if (pr.user.id !== 46447321) {\n              console.log('Not an all-contributors pull request');\n              return;\n            }\n\n            console.log(`Merging pull request: ${pr.html_url}`);\n            await github.rest.pulls.merge({\n              owner, repo,\n              pull_number: pr.number,\n              merge_method: \"rebase\",\n            });\n"
  },
  {
    "path": ".github/workflows/microsoft_store.yml",
    "content": "name: Windows Store\non:\n  release:\n    types: [published]\n\njobs:\n  microsoft_store:\n    name: Publish To Windows Store\n    runs-on: ubuntu-latest\n    steps:\n      - name: Configure Store Credentials 🔑\n        uses: jandedobbeleer/store-submission@submission-status\n        with:\n          command: configure\n          type: win32\n          seller-id: ${{ secrets.SELLER_ID }}\n          product-id: ${{ secrets.PRODUCT_ID }}\n          tenant-id: ${{ secrets.TENANT_ID }}\n          client-id: ${{ secrets.CLIENT_ID }}\n          client-secret: ${{ secrets.CLIENT_SECRET }}\n          only-on-ready: true\n      - name: Update draft submission\n        uses: jandedobbeleer/store-submission@submission-status\n        with:\n          command: update\n          product-update: '{\n            \"packages\":[\n            {\n            \"packageUrl\":\"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/${{ github.event.release.tag_name }}/install-x64.msi\",\n            \"languages\":[\"en\"],\n            \"architectures\":[\"X64\"],\n            \"installerParameters\":\"/quiet INSTALLER=ws\",\n            \"isSilentInstall\":false\n            },\n            {\n            \"packageUrl\":\"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/${{ github.event.release.tag_name }}/install-arm64.msi\",\n            \"languages\":[\"en\"],\n            \"architectures\":[\"Arm64\"],\n            \"installerParameters\":\"/quiet INSTALLER=ws\",\n            \"isSilentInstall\":false\n            }\n            ]\n            }'\n      - name: Publish Submission\n        uses: jandedobbeleer/store-submission@submission-status\n        with:\n          command: publish\n"
  },
  {
    "path": ".github/workflows/publish-mcp.yml",
    "content": "name: Publish to MCP Registry\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - 'website/api/mcp/**'\n  workflow_dispatch:\n\njobs:\n  publish:\n    name: Publish MCP Server\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write  # Required for OIDC authentication\n      contents: read\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n        with:\n          fetch-depth: 0  # Fetch all tags\n\n      - name: Extract version from latest git tag\n        id: version\n        run: |\n          # Get the latest git tag (without 'v' prefix)\n          VERSION=$(git describe --tags --abbrev=0 | sed 's/^v//')\n          echo \"version=$VERSION\" >> $GITHUB_OUTPUT\n          echo \"Using version from git tag: $VERSION\"\n\n      - name: Update server.json version\n        run: |\n          cd website/api/mcp\n          jq --arg v \"${{ steps.version.outputs.version }}\" '.version = $v' server.json > tmp.json && mv tmp.json server.json\n          echo \"Updated server.json version to ${{ steps.version.outputs.version }}\"\n          cat server.json\n\n      - name: Validate server.json\n        run: |\n          cd website/api\n          npm ci\n          cd mcp\n          node validate-server.js\n\n      - name: Install MCP Publisher\n        run: |\n          curl -L \"https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz\" | tar -xzf -\n          chmod +x mcp-publisher\n          ./mcp-publisher --version\n\n      - name: Login to MCP Registry\n        env:\n          MCP_REGISTRY_PEM: ${{ secrets.MCP_REGISTRY_PEM }}\n        run: |\n          echo \"$MCP_REGISTRY_PEM\" > key.pem\n          PRIVATE_KEY=$(openssl pkey -in key.pem -noout -text | grep -A3 \"priv:\" | tail -n +2 | tr -d ' :\\n')\n          ./mcp-publisher login dns --domain ohmyposh.dev --private-key \"$PRIVATE_KEY\"\n          rm -f key.pem\n\n      - name: Publish to MCP Registry\n        run: |\n          cd website/api/mcp\n          ../../../mcp-publisher publish\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches:\n      - main\n    paths:\n      - \"src/**\"\n      - \"packages/**\"\n      - \".github/workflows/**\"\n  workflow_dispatch:\n\nconcurrency:\n  group: ${{ github.workflow }}\n\njobs:\n  changelog:\n    runs-on: ubuntu-latest\n    outputs:\n      version: ${{ steps.changelog.outputs.version }}\n      body: ${{ steps.changelog.outputs.clean_changelog }}\n      tag: ${{ steps.changelog.outputs.tag }}\n      skipped: ${{ steps.changelog.outputs.skipped }}\n    steps:\n      - name: Checkout code 👋\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n      - name: Create changelog ✍️\n        id: changelog\n        uses: TriPSs/conventional-changelog-action@91be4f3188da74fe85de9caffcebc80b26d43b5b\n        with:\n          github-token: ${{ secrets.github_token }}\n          skip-version-file: \"true\"\n          output-file: \"false\"\n          skip-commit: \"true\"\n          skip-on-empty: \"true\"\n          skip-tag: \"true\"\n\n  artifacts:\n    needs: changelog\n    if: ${{ needs.changelog.outputs.skipped == 'false' }}\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: pwsh\n        working-directory: ${{ github.workspace }}/build\n    steps:\n      - name: Checkout code 👋\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n      - name: Install Go 🗳\n        uses: ./.github/workflows/composite/bootstrap-go\n      - name: Pre Build 😸\n        env:\n          SIGNING_KEY: ${{ secrets.SIGNING_KEY }}\n        run: |\n          ./pre.ps1 -Version ${{ needs.changelog.outputs.version }} -SDKVersion \"10.0.26100.0\"\n      - name: Run GoReleaser 🚀\n        uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29\n        with:\n          distribution: goreleaser\n          version: v2.3.2\n          args: release --clean --skip publish\n          workdir: src\n        env:\n          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}\n          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}\n          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}\n      - name: Post Build 🤐\n        run: |\n          ./post.ps1\n      - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f\n        with:\n          name: build-artifacts\n          path: |\n            src/dist/posh-*\n            src/dist/themes.*\n            src/dist/checksums.*\n  msi:\n    needs:\n      - changelog\n      - artifacts\n    runs-on: windows-latest\n    strategy:\n      matrix:\n        arch: [x64, arm64]\n    defaults:\n      run:\n        shell: pwsh\n        working-directory: ${{ github.workspace }}/packages/msi\n    steps:\n      - name: Checkout code 👋\n        uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98\n      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c\n        with:\n          name: build-artifacts\n          path: dist\n      - name: Install Wix Toolset 🛠\n        run: dotnet tool install --global wix\n      - name: Build installer 📦\n        id: build\n        env:\n          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}\n          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}\n          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}\n        run: |\n          $version = '${{ needs.changelog.outputs.version }}'.TrimStart(\"v\")\n          ./build.ps1 -Architecture ${{ matrix.arch }}  -Version $version -Copy -Sign -SDKVersion \"10.0.26100.0\"\n      - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f\n        with:\n          name: msi-artifact-${{ matrix.arch }}\n          path: |\n            packages/msi/out/install-${{ matrix.arch }}.msi\n            packages/msi/out/install-${{ matrix.arch }}.msix\n  release:\n    runs-on: ubuntu-latest\n    needs:\n      - changelog\n      - artifacts\n      - msi\n    steps:\n      - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c\n        with:\n          merge-multiple: true\n      - name: Upload version file\n        env:\n          AZURE_STORAGE_CONNECTION_STRING: ${{ secrets.CDN_CONNECTIONSTRING }}\n        run: |\n          echo v${{ needs.changelog.outputs.version }} > version.txt\n          az storage blob upload-batch --destination releases/v${{ needs.changelog.outputs.version }} --source .\n          az storage blob upload-batch --destination releases/latest --overwrite true --source .\n      - name: Release 🎓\n        uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe\n        with:\n          tag_name: ${{ needs.changelog.outputs.tag }}\n          body: ${{ needs.changelog.outputs.body }}\n          fail_on_unmatched_files: true\n          token: ${{ secrets.GH_PAT }}\n          files: |\n            *\n  winget:\n    runs-on: windows-latest\n    needs:\n      - changelog\n      - release\n    env:\n      WINGETCREATE_TOKEN: ${{ secrets.WINGETCREATE_TOKEN }}\n    steps:\n    - name: Create manifest and submit PR 📦\n      shell: pwsh\n      run: |\n        Write-Host \"Preparing to submit to WinGet repository...\" -ForegroundColor Green\n\n        # Install the latest wingetcreate exe\n        # Need to do things this way, see https://github.com/PowerShell/PowerShell/issues/13138\n        Write-Verbose \"Importing Appx module using Windows PowerShell compatibility\"\n        Import-Module Appx -UseWindowsPowerShell -ErrorAction Stop\n\n        # Download and install Winget-Create msixbundle\n        $appxBundleFile = Join-Path -Path $env:TEMP -ChildPath \"wingetcreate.msixbundle\"\n        Write-Verbose \"Downloading wingetcreate to: $appxBundleFile\"\n\n        Invoke-WebRequest -Uri \"https://aka.ms/wingetcreate/latest/msixbundle\" -OutFile $appxBundleFile -ErrorAction Stop\n        Add-AppxPackage -Path $appxBundleFile -ErrorAction Stop\n\n        Write-Verbose \"Successfully installed wingetcreate\"\n\n        # Submit the PR to WinGet repository\n        Write-Host \"Submitting pull request to WinGet repository...\" -ForegroundColor Green\n\n        $version = \"${{ needs.changelog.outputs.tag }}\"\n        $version = $version.TrimStart('v')\n\n        $urls = @(\n            \"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v$version/install-x64.msi|x64\",\n            \"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v$version/install-x64.msix|x64\",\n            \"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v$version/install-arm64.msi|arm64\",\n            \"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v$version/install-arm64.msix|arm64\"\n        )\n\n        wingetcreate update JanDeDobbeleer.OhMyPosh --version $version --token $env:WINGETCREATE_TOKEN --submit --urls $urls\n"
  },
  {
    "path": ".github/workflows/vale.yml",
    "content": "name: Vale\n\non: [pull_request]\n\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: true\n\njobs:\n  vale:\n    name: runner / vale\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 # v4\n      - name: Install Vale\n        run: |\n          curl -sfL https://github.com/errata-ai/vale/releases/download/v3.13.1/vale_3.13.1_Linux_64-bit.tar.gz | tar -xz\n          sudo mv vale /usr/local/bin/vale\n      - name: Sync Vale packages\n        run: vale sync\n      - name: Lint\n        run: vale AGENTS.md .github/copilot-instructions.md .github/skills\n"
  },
  {
    "path": ".gitignore",
    "content": "# APM\napm_modules/\n.github/skills/*\n!.github/skills/segment-create/\n!.github/skills/segment-docs/\n\n# Others\n\n.specs/\n.fleet/\nsrc/test/umbraco/obj/\nsrc/keys\n*.prof\n*.wixpdb\npackages/msi/Microsoft.Trusted.Signing.Client\n.claude\n.styles\n\n# Created by https://www.toptal.com/developers/gitignore/api/node,go,visualstudiocode\n# Edit at https://www.toptal.com/developers/gitignore?templates=node,go,visualstudiocode\n\n### Go ###\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Windows asset files\n/src/rsrc_windows_*.syso\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\n\n### Go Patch ###\n/vendor/\n/Godeps/\n\n### Node ###\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# Next.js build output\n.next\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n### VisualStudioCode ###\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n*.code-workspace\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n\n# End of https://www.toptal.com/developers/gitignore/api/node,go,visualstudiocode\n\n# linux binary\n/src/oh-my-posh\npackage/\nbin/\nOutput/\n*.sha256\n*.7z\n\n# images\n*.png\n\n# go releaser\n/src/dist\n\n\n# Created by https://www.toptal.com/developers/gitignore/api/windows,linux,macos\n# Edit at https://www.toptal.com/developers/gitignore?templates=windows,linux,macos\n\n### Linux ###\n*~\n\n# temporary files which can be created if a process still has a handle open of a deleted file\n.fuse_hidden*\n\n# KDE directory preferences\n.directory\n\n# Linux trash folder which might appear on any partition or disk\n.Trash-*\n\n# .nfs files are created when an open file is removed but is still being accessed\n.nfs*\n\n### macOS ###\n# General\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n\n# Thumbnails\n._*\n\n# Files that might appear in the root of a volume\n.DocumentRevisions-V100\n.fseventsd\n.Spotlight-V100\n.TemporaryItems\n.Trashes\n.VolumeIcon.icns\n.com.apple.timemachine.donotpresent\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n### Windows ###\n# Windows thumbnail cache files\nThumbs.db\nThumbs.db:encryptable\nehthumbs.db\nehthumbs_vista.db\n\n# Dump file\n*.stackdump\n\n# Folder config file\n[Dd]esktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msix\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# End of https://www.toptal.com/developers/gitignore/api/windows,linux,macos\n\n# Keys\n\ncosign.key\n\n*.omp.json.bak\n\n__debug_bin\nsrc/src\n"
  },
  {
    "path": ".markdownlint-cli2.yaml",
    "content": "config:\n  MD013:\n    line_length: 120\n    code_blocks: false\n  MD024: false\nfix: true\ngitignore: true\nignores:\n  - node_modules/\n  - .github/agents/segment-docs.md\n  - .github/agents/architecture.md\n  - .github/PULL_REQUEST_TEMPLATE.md\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"trailingComma\": \"none\",\n  \"overrides\": [\n    {\n      \"files\": [\"*.jsonc\", \"*.json\"],\n      \"options\": {\n        \"parser\": \"json\",\n        \"trailingComma\": \"none\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".vale.ini",
    "content": "StylesPath = .styles\n\nMinAlertLevel = suggestion\n\nPackages = https://github.com/tbhb/vale-ai-tells/releases/download/v1.4.0/ai-tells.zip, https://github.com/HeyItsGilbert/vale-agentic/releases/download/v2.0.0/agentic.zip\n\n[*.{md}]\n# ^ This section applies to only Markdown files.\n#\n# You can change (or add) file extensions here\n# to apply these settings to other file types.\n#\n# For example, to apply these settings to both\n# Markdown and reStructuredText:\n#\n# [*.{md,rst}]\nBasedOnStyles = ai-tells, agentic\n"
  },
  {
    "path": ".versionrc.json",
    "content": "{\n  \"types\": [\n    {\n      \"type\": \"feat\",\n      \"section\": \"Features\"\n    },\n    {\n      \"type\": \"fix\",\n      \"section\": \"Bug Fixes\"\n    },\n    {\n      \"type\": \"refactor\",\n      \"section\": \"Refactor\"\n    },\n    {\n      \"type\": \"revert\",\n      \"section\": \"Reverts\"\n    },\n    {\n      \"type\": \"theme\",\n      \"section\": \"Themes\"\n    },\n    {\n      \"type\": \"chore\",\n      \"hidden\": true\n    },\n    {\n      \"type\": \"ci\",\n      \"hidden\": true\n    },\n    {\n      \"type\": \"chore\",\n      \"hidden\": true\n    },\n    {\n      \"type\": \"docs\",\n      \"hidden\": true\n    },\n    {\n      \"type\": \"perf\",\n      \"hidden\": true\n    },\n    {\n      \"type\": \"test\",\n      \"hidden\": true\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  \"recommendations\": [\n    \"bmalehorn.vscode-fish\",\n    \"davidanson.vscode-markdownlint\",\n    \"elves.elvish\",\n    \"esbenp.prettier-vscode\",\n    \"github.vscode-pull-request-github\",\n    \"golang.go\",\n    \"jnoortheen.xonsh\",\n    \"ms-azuretools.vscode-azurefunctions\",\n    \"ms-vscode.powershell\",\n    \"redhat.vscode-yaml\",\n    \"sumneko.lua\",\n    \"tamasfe.even-better-toml\",\n    \"yzhang.markdown-all-in-one\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"name\": \"Primary\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"print\",\n        \"primary\",\n        \"--shell=pwsh\",\n        \"--terminal-width=200\"\n      ]\n    },\n    {\n      \"name\": \"Tooltip\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"print\",\n        \"tooltip\",\n        \"--command=git\",\n        \"--shell=pwsh\"\n      ]\n    },\n    {\n      \"name\": \"Transient\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"print\",\n        \"transient\",\n        \"--shell=pwsh\",\n        \"--status=1\"\n      ]\n    },\n    {\n      \"name\": \"Launch tests\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"test\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"--test.v\"\n      ]\n    },\n    {\n      \"name\": \"Debug\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"debug\"\n      ]\n    },\n    {\n      \"name\": \"Init\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"init\",\n        \"cmd\",\n        \"--print\"\n      ]\n    },\n    {\n      \"name\": \"Export Config\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"config\",\n        \"export\"\n      ]\n    },\n    {\n      \"name\": \"Export Image\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"config\",\n        \"export\",\n        \"image\"\n      ]\n    },\n    {\n      \"name\": \"Migrate config\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"config\",\n        \"migrate\"\n      ]\n    },\n    {\n      \"name\": \"Migrate glyphs\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"config\",\n        \"migrate\",\n        \"glyphs\"\n      ]\n    },\n    {\n      \"name\": \"Get value\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"get\",\n        \"accent\"\n      ]\n    },\n    {\n      \"name\": \"Toggle segment\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"toggle\",\n        \"git\"\n      ]\n    },\n    {\n      \"name\": \"Notice\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"notice\"\n      ]\n    },\n    {\n      \"name\": \"Upgrade\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"upgrade\"\n      ]\n    },\n    {\n      \"name\": \"Font install\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"font\",\n        \"install\",\n        \"AnonymousPro\"\n      ]\n    },\n    {\n      \"name\": \"Auth YTMDA\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"auth\",\n        \"ytmda\"\n      ]\n    },\n    {\n      \"name\": \"DSC schema\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"font\",\n        \"dsc\",\n        \"schema\"\n      ]\n    },\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Theme export\",\n      \"cwd\": \"${workspaceFolder}/website\",\n      \"program\": \"${workspaceRoot}/website/export_themes.mjs\",\n      \"console\": \"integratedTerminal\"\n    },\n    {\n      \"type\": \"node\",\n      \"request\": \"launch\",\n      \"name\": \"Bluesky\",\n      \"cwd\": \"${workspaceFolder}/scripts/bluesky\",\n      \"program\": \"${workspaceRoot}/scripts/bluesky/main.cjs\",\n      \"console\": \"integratedTerminal\",\n      \"envFile\": \"${workspaceFolder}/scripts/bluesky/.env\"\n    },\n    {\n      \"name\": \"Docs API\",\n      \"type\": \"node\",\n      \"request\": \"attach\",\n      \"port\": 9229,\n      \"preLaunchTask\": \"func: host start\",\n      \"cwd\": \"${workspaceFolder}/website\",\n      \"envFile\": \"${workspaceFolder}/website/.env\"\n    },\n    {\n      \"name\": \"Cache clear\",\n      \"type\": \"go\",\n      \"request\": \"launch\",\n      \"mode\": \"debug\",\n      \"program\": \"${workspaceRoot}/src\",\n      \"args\": [\n        \"cache\",\n        \"clear\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"go.lintTool\": \"golangci-lint\",\n  \"go.useLanguageServer\": true,\n  \"go.testOnSave\": true,\n  \"[go]\": {\n    \"editor.formatOnSave\": true,\n    \"editor.codeActionsOnSave\": {\n      \"source.organizeImports\": \"explicit\"\n    }\n  },\n  \"go.formatTool\": \"gofmt\",\n  \"go.formatFlags\": [\n    \"-s\"\n  ],\n  \"azureFunctions.deploySubpath\": \"docs/api\",\n  \"azureFunctions.postDeployTask\": \"npm install (functions)\",\n  \"azureFunctions.projectLanguage\": \"JavaScript\",\n  \"azureFunctions.projectRuntime\": \"~4\",\n  \"debug.internalConsoleOptions\": \"neverOpen\",\n  \"azureFunctions.projectSubpath\": \"docs/api\",\n  \"azureFunctions.preDeployTask\": \"npm prune (functions)\",\n  \"[markdown]\": {\n    \"editor.formatOnSave\": true,\n    \"editor.formatOnPaste\": true,\n    \"editor.codeActionsOnSave\": {\n      \"source.fixAll.markdownlint\": \"explicit\"\n    }\n  },\n  \"files.encoding\": \"utf8\",\n  \"[powershell]\": {\n    \"files.encoding\": \"utf8\"\n  }\n}\n"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n  // See https://go.microsoft.com/fwlink/?LinkId=733558\n  // for the documentation about the tasks.json format\n  \"version\": \"2.0.0\",\n  \"cwd\": \"${workspaceRoot}\",\n  \"echoCommand\": true,\n  \"type\": \"shell\",\n  \"tasks\": [\n    {\n      \"type\": \"shell\",\n      \"command\": \"go\",\n      \"label\": \"build oh-my-posh\",\n      \"detail\": \"Build oh-my-posh in the /src folder locally\",\n      \"options\": {\n        \"cwd\": \"${workspaceRoot}/src\"\n      },\n      \"group\": {\n        \"kind\": \"build\",\n        \"isDefault\": true\n      },\n      \"problemMatcher\": \"$go\",\n      \"args\": [\n        \"build\",\n        \"-v\"\n      ]\n    },\n    {\n      \"type\": \"shell\",\n      \"command\": \"go\",\n      \"label\": \"devcontainer: rebuild oh-my-posh\",\n      \"detail\": \"Build oh-my-posh for all shells when inside the devcontainer\",\n      \"options\": {\n        \"cwd\": \"${workspaceRoot}/src\",\n        \"shell\": {\n          \"executable\": \"bash\",\n          \"args\": [\n            \"-c\"\n          ]\n        },\n        \"statusbar\": {\n          \"hide\": false,\n          \"color\": \"#22C1D6\",\n          \"label\": \"$(beaker) devcontainer: rebuild oh-my-posh\",\n          \"tooltip\": \"Compiles *oh-my-posh* from this repo while **overwriting** your preinstalled stable release.\"\n        }\n      },\n      \"group\": \"build\",\n      \"problemMatcher\": \"$go\",\n      \"args\": [\n        \"build\",\n        \"-v\",\n        \"-o\",\n        \"/home/vscode/bin/oh-my-posh\",\n        \"-ldflags\",\n        \"\\\"-s -w -X 'github.com/jandedobbeleer/oh-my-posh/src/build.Version=development-$(git --no-pager log -1 --pretty=%h-%s)' -extldflags '-static'\\\"\"\n      ]\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"start\",\n      \"path\": \"website/\",\n      \"problemMatcher\": [],\n      \"label\": \"website: start\",\n      \"detail\": \"cross-env NODE_ENV=development docusaurus start\"\n    },\n    {\n      \"type\": \"func\",\n      \"command\": \"host start\",\n      \"problemMatcher\": \"$func-node-watch\",\n      \"isBackground\": true,\n      \"dependsOn\": \"npm install (functions)\",\n      \"options\": {\n        \"cwd\": \"${workspaceFolder}/website/api\"\n      }\n    },\n    {\n      \"type\": \"shell\",\n      \"label\": \"npm install (functions)\",\n      \"command\": \"npm install\",\n      \"options\": {\n        \"cwd\": \"${workspaceFolder}/website/api\"\n      }\n    },\n    {\n      \"type\": \"shell\",\n      \"label\": \"npm prune (functions)\",\n      \"command\": \"npm prune --production\",\n      \"problemMatcher\": [],\n      \"options\": {\n        \"cwd\": \"${workspaceFolder}/website/api\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Agent Instructions\n\n## APM Setup\n\nThis repository uses [APM](https://github.com/JanDeDobbeleer/agentic) to manage agent skills.\nBefore starting any task, verify that the skills listed in `apm.yml` are installed under\nthe `apm_modules/` directory.\n\nIf `apm_modules/` is missing or any skill package from `apm.yml` is not present, install them by running:\n\n```sh\npip install apm-cli\napm install\n```\n\n## General File Creation Guidelines\n\nWhen creating new files:\n\n- **Always use LF (Unix-style) line endings**, not CRLF (Windows-style)\n- This repository uses `.gitattributes` to enforce LF line endings\n- Ensures consistency across all platforms and avoids Git warnings\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement by reaching out\nvia [email](mailto:abuse@ohmyposh.dev).\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.0, available [in the documentation][version-2].\n\nCommunity Impact Guidelines were inspired by [Mozilla's code of conduct\nenforcement ladder][moz-div].\n\nFor answers to common questions about this code of conduct, see the [FAQ][faq].\nTranslations are available [in the documentation][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[moz-div]: https://github.com/mozilla/diversity\n[version-2]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html\n[faq]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nNote we have a code of conduct, please follow it in all your interactions with the project.\n\n> [!NOTE]\n> Theme additions are no longer accepted due to the ever growing set.\n> We do however accept showcasing your custom theme in the [themes discussion section here][themes-discussion]\n> or the [themes channel on Discord][discord-link].\n\nEnsure you've read through the [documentation][docs] so you understand the core concepts of the\nproject. If you're looking to get familiar with go, following the getting started [guide][guide]\ncan be a good starting point.\n\n## Setting Up Agents and Skills\n\nThis project uses [APM (Agent Package Manager)][apm] to manage shared AI agent skills.\nProject-specific skills live in `.github/skills/`, while shared skills are declared\nin `apm.yml` and installed via APM.\n\n### Install APM\n\n```bash\ncurl -sSL https://raw.githubusercontent.com/microsoft/apm/main/install.sh | sh\n```\n\nAlternatively, install via Homebrew or pip:\n\n```bash\nbrew install microsoft/apm/apm\n# or\npip install apm-cli\n```\n\n### Install Skills\n\nAfter cloning the repository, run:\n\n```bash\napm install\n```\n\nThis pulls in the shared skills from [JanDeDobbeleer/agentic][agentic] (conventional commits,\nGo, Markdown, and PowerShell conventions). The project-specific skills (segment-create and\nsegment-docs) are already included in the repository.\n\n## Pull Request Process\n\n1. Ensure any dependencies or build artifacts are removed/ignored before creating a commit.\n2. Commits follow the [conventional commits][cc] guidelines.\n(You can [look up the supported *types*][cc-types] along with an explanation [in the documentation][cc-types])\n3. Update the documentation with details of changes to the functionality, this includes new segments\n   or core functionality.\n4. Pull Requests are merged once all checks pass and a project maintainer has approved it.\n\n## Codespaces / Devcontainer Development Environment\n\nArguably the easiest way to contribute anything is to use our prepared development environment.\n\nWe have a `.devcontainer/devcontainer.json` file, meaning we are compatible with:\n\n- [![Open in GitHub Codespaces][codespaces-badge]][codespaces-link], or\n- the [Visual Studio Code Remote - Containers][devcontainer-ext] extension.\n\nThis Linux environment includes all shells supported by oh-my-posh, including Bash, ZSH,\nFish and PowerShell, the latter of which is the default.\n\n### Configuring Devcontainer's Timezone & Theme\n\n1. Open the [`.devcontainer/devcontainer.json`][devcontainer] file and in the \"*build*\" section modify:\n\n   - `TZ`: with [your own timezone][timezones]\n\n2. Summon the Command Panel (Ctrl+Shift+P) and select `Codespaces: Rebuild Container`\n   to rebuild your devcontainer. (This should take just a few seconds.)\n\n### Recompiling oh-my-posh\n\nThe devcontainer definition preinstalls the latest stable oh-my-posh release at build time.\n\nTo overwrite the installation's version inside the running devcontainer, you may use the\nVSCode *task* `devcontainer: build omp` to rebuild your oh-my-posh with that of\nyour running repository's state. (You might see a button for this in your statusbar.)\n\nIf the compile succeeds, `oh-my-posh --version` should reply:\n`development`\n\nShould you somehow mess up your devcontainer's OMP install catastrophically, remember that\nif you do `Codespaces: Rebuild Container` again, you'll be back to the latest stable release.\n\n## Local development\n\nMake sure your local go version matches with the pinned version in [go.mod]. You can build\noh-my-posh by navigating the to the `/src` folder and executing the following command.\n\n```bash\ngo build -v -o /path/to/oh-my-posh(.exe)\n```\n\n### Running tests\n\nTo execute the tests, run the following command from the `/src` folder.\n\n```bash\ngo test \"./...\"\n```\n\n[themes-discussion]: [https://github.com/JanDeDobbeleer/oh-my-posh/discussions/categories/themes]\n[discord-link]: [https://discord.com/channels/1023597603331526656/1055533233309233252]\n[docs]: <https://ohmyposh.dev/docs>\n[guide]: <https://ohmyposh.dev/docs/contributing/started>\n[cc]: <https://www.conventionalcommits.org/en/v1.0.0/#summary>\n[cc-types]: <https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/.commitlintrc.yml#L23-L33>\n[codespaces-badge]: <https://github.com/codespaces/badge.svg>\n[codespaces-link]: <https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=175405157>\n[devcontainer-ext]: <https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers>\n[timezones]: <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>\n[devcontainer]: .devcontainer/devcontainer.json\n[go.mod]: src/go.mod\n[apm]: https://github.com/microsoft/apm\n[agentic]: https://github.com/JanDeDobbeleer/agentic\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright 2022 Jan De Dobbeleer\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,\nand to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<!-- markdownlint-disable -->\n<p align=\"center\">\n  <img\n    width=\"400\"\n    src=\"https://raw.githubusercontent.com/jandedobbeleer/oh-my-posh/main/website/static/img/logo.png\"\n    alt=\"Oh My Posh logo – Prompt theme engine for any shell\"\n  />\n</p>\n<!-- markdownlint-enable -->\n\n![MIT license badge](https://img.shields.io/github/license/JanDeDobbeleer/oh-my-posh.svg)\n\n![Build Status badge](https://img.shields.io/github/actions/workflow/status/jandedobbeleer/oh-my-posh/release.yml?branch=main)\n\n[![Release version number badge][release-badge]][release]\n\n[![Documentation link badge ohmyposh.dev][docs-badge]][docs]\n\n![Number of GitHub Downloads badge](https://img.shields.io/github/downloads/jandedobbeleer/oh-my-posh/total?color=pink&label=GitHub%20Downloads)\n\nThis repo was made with love using GitKraken.\n\n[![GitKraken shield][kraken]][kraken-ref]\n<!-- markdownlint-disable first-header-h1 -->\n\n## Sponsors\n\n[![Documentation link badge ohmyposh.dev][merge-conflict-logo]][merge-conflict]\n\n[Want to become a sponsor?][sponsor-link]\n\n## Join the community\n\n![Mastodon badge](https://img.shields.io/mastodon/follow/110275292073181892?domain=https%3A%2F%2Fhachyderm.io&label=Mastodon&style=social)\n\n![Discord badge](https://img.shields.io/discord/1023597603331526656)\n\nWhat started as the offspring of [oh-my-posh2](https://github.com/JanDeDobbeleer/oh-my-posh2) for PowerShell\nresulted in a cross platform, highly customizable and extensible prompt theme engine. After 4 years of working\non oh-my-posh, a modern and more efficient tool was needed to suit my personal needs.\n\n## :heart: Support :heart:\n\n[![Swag][swag-badge]][swag] - Show your love with a t-shirt!\n\n[![GitHub][github-badge]][github-sponsors] - One time support, or a recurring donation?\n\n[![Ko-Fi][kofi-badge]][kofi] - No coffee, no code.\n\n## Features\n\n* Shell and platform agnostic\n* Easily configurable\n* The __most__ configurable prompt utility\n* Fast\n* Secondary prompt\n* Right prompt\n* Transient prompt\n\n## Documentation\n\n[![Documentation][docs-badge]][docs]\n\n## Reviews\n\n* [Repo review](https://repo-reviews.github.io//reviews/2023-06-21_TameWizard_JanDeDobbeleer_oh-my-posh) by [TameWizard](https://github.com/TameWizard)\n\n## Thanks\n\n* [Chris Benti](https://github.com/chrisbenti/PS-Config) providing the first influence to start oh-my-posh\n* [Keith Dahlby](https://github.com/dahlbyk/posh-git) for creating posh-git and making life more enjoyable\n* [Robby Russell](https://github.com/ohmyzsh/ohmyzsh) for creating oh-my-zsh, without him this would probably not be here\n* [Janne Mareike Koschinski](https://github.com/justjanne) for providing information on how to get certain information\nusing Go (and the amazing [README](https://github.com/justjanne/powerline-go))\n* [Starship](https://github.com/starship/starship/blob/master/src/init/mod.rs) for doing great things\n\n[kraken]: https://img.shields.io/badge/GitKraken-Legendary%20Git%20Tools-teal?style=plastic&logo=gitkraken\n[kraken-ref]: https://www.gitkraken.com/invite/nQmDPR9D\n[swag-badge]: https://img.shields.io/badge/Swag-Get%20some!-blue\n[swag]: https://swag.ohmyposh.dev\n[github-badge]: https://img.shields.io/badge/-Sponsor-fafbfc?logo=GitHub%20Sponsors\n[github-sponsors]: https://github.com/sponsors/JanDeDobbeleer\n[kofi-badge]: https://img.shields.io/badge/Ko--fi-Buy%20me%20a%20coffee!-%2346b798.svg\n[kofi]: https://ko-fi.com/jandedobbeleer\n[docs-badge]: https://img.shields.io/badge/Docs-ohmyposh.dev-blue\n[docs]: https://ohmyposh.dev\n[release-badge]: https://img.shields.io/github/v/release/jandedobbeleer/oh-my-posh?label=Release\n[release]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest\n\n[merge-conflict]: https://www.mergeconflict.fm/\n[merge-conflict-logo]: https://media24.fireside.fm/file/fireside-images-2024/podcasts/images/0/02d84890-e58d-43eb-ab4c-26bcc8524289/cover_small.jpg?v=1\n[sponsor-link]: https://buy.polar.sh/polar_cl_qnmZxboq1IDUJo03mk2Jue6ktqZrCXElnzH2s2xbV2R\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nOnly the latest [release][releases] is supported.\n\n## Reporting a Vulnerability\n\nVulnerabilities can be sent in via [email][email] to avoid publishing in the open.\nOh My Posh does not have a bounty program, neither do we respond to bug bounties.\n\nFor valid security concerns, you can expect a response within 48 hours,\nand credit is given once an acceptable fix is found and published.\n\n[releases]: https://github.com/JanDeDobbeleer/oh-my-posh/releases\n[email]: mailto:security@ohmyposh.dev\n"
  },
  {
    "path": "apm.lock.yaml",
    "content": "lockfile_version: '1'\ngenerated_at: '2026-03-15T08:59:17.859220+00:00'\napm_version: 0.7.9\ndependencies:\n- repo_url: JanDeDobbeleer/agentic\n  host: github.com\n  resolved_commit: dfc3f6e80eae907b2ad0562b072386034171d5fe\n  virtual_path: skills/conventional-commit\n  is_virtual: true\n  package_type: claude_skill\n  deployed_files:\n  - .github/skills/conventional-commit\n- repo_url: JanDeDobbeleer/agentic\n  host: github.com\n  resolved_commit: dfc3f6e80eae907b2ad0562b072386034171d5fe\n  virtual_path: skills/golang\n  is_virtual: true\n  package_type: claude_skill\n  deployed_files:\n  - .github/skills/golang\n- repo_url: JanDeDobbeleer/agentic\n  host: github.com\n  resolved_commit: dfc3f6e80eae907b2ad0562b072386034171d5fe\n  virtual_path: skills/markdown\n  is_virtual: true\n  package_type: claude_skill\n  deployed_files:\n  - .github/skills/markdown\n- repo_url: JanDeDobbeleer/agentic\n  host: github.com\n  resolved_commit: dfc3f6e80eae907b2ad0562b072386034171d5fe\n  virtual_path: skills/powershell\n  is_virtual: true\n  package_type: claude_skill\n  deployed_files:\n  - .github/skills/powershell\n"
  },
  {
    "path": "apm.yml",
    "content": "name: oh-my-posh\nversion: 1.0.0\ndescription: A prompt theme engine for any shell.\n\ndependencies:\n  apm:\n    - JanDeDobbeleer/agentic/skills/conventional-commit\n    - JanDeDobbeleer/agentic/skills/golang\n    - JanDeDobbeleer/agentic/skills/markdown\n    - JanDeDobbeleer/agentic/skills/powershell\n    - JanDeDobbeleer/agentic/skills/vale-user-facing-text\n"
  },
  {
    "path": "build/post.ps1",
    "content": "# Description: Post build script to compress the themes and generate SHA256 hashes for all files in the dist folder\n\n# Compress all themes\n$compress = @{\n    Path             = \"../themes/*.omp.*\"\n    CompressionLevel = \"Fastest\"\n    DestinationPath  = \"../src/dist/themes.zip\"\n}\nCompress-Archive @compress\n\n# Generate SHA256 hashes for all files in the dist folder\nGet-ChildItem ./dist -Exclude *.yaml, *.sig | Get-Unique |\nForeach-Object {\n    $zipHash = Get-FileHash $_.FullName -Algorithm SHA256\n    $zipHash.Hash | Out-File -Encoding 'UTF8' \"../src/dist/$($_.Name).sha256\"\n}\n"
  },
  {
    "path": "build/pre.ps1",
    "content": "Param\n(\n    [string]\n    $Version,\n    [parameter(Mandatory = $false)]\n    [string]\n    $SDKVersion = \"10.0.26100.0\"\n)\n\ngit config --global user.name \"GitHub Actions\"\ngit config --global user.email \"41898282+github-actions[bot]@users.noreply.github.com\"\ngit tag $Version --force\n\n$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'\n\n$shaSigningKeyLocation = Join-Path -Path $env:RUNNER_TEMP -ChildPath sha_signing_key.pem\n$env:SIGNING_KEY > $shaSigningKeyLocation\nWrite-Output \"SHA_SIGNING_KEY_LOCATION=$shaSigningKeyLocation\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n# install code signing dlib\nnuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.92 -ExcludeVersion -OutputDirectory $env:RUNNER_TEMP\nWrite-Output \"SIGNTOOLDLIB=$env:RUNNER_TEMP/Microsoft.Trusted.Signing.Client/bin/x64/Azure.CodeSigning.Dlib.dll\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n# requires Windows Dev Kit 10.0.26100.0\n$signtool = \"C:/Program Files (x86)/Windows Kits/10/bin/$SDKVersion/x64/signtool.exe\"\nWrite-Output \"SIGNTOOL=$signtool\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n\n# openssl\n$openssl = 'C:/Program Files/Git/usr/bin/openssl.exe'\nWrite-Output \"OPENSSL=$openssl\" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append\n"
  },
  {
    "path": "packages/msi/README.md",
    "content": "# MSI Package\n\n## Prerequisites\n\n- [dotnet]\n- [wix]: `dotnet tool install --global wix`\n\n## Build the package\n\nThis guide assumes and advices the use of PowerShell as your shell environment for this purpose.\n\n### Set the environment variables\n\n```powershell\n$env:VERSION = \"1.3.37\"\n```\n\n### Build the installer\n\n```powershell\nwix build -arch arm64 -out install-arm64.msi\n```\n\n## Install the package\n\n### For the current user\n\n```powershell\ninstall-arm64.msi\n```\n\n### For all users\n\n```powershell\ninstall-arm64.msi ALLUSERS=1\n```\n\n[dotnet]: https://dotnet.microsoft.com/en-us/download/dotnet?cid=getdotnetcorecli\n[wix]: https://wixtoolset.org/docs/intro/\n"
  },
  {
    "path": "packages/msi/appxmanifest.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Package xmlns=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10\" xmlns:rescap=\"http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities\" xmlns:uap=\"http://schemas.microsoft.com/appx/manifest/uap/windows10\" xmlns:uap3=\"http://schemas.microsoft.com/appx/manifest/uap/windows10/3\" xmlns:uap5=\"http://schemas.microsoft.com/appx/manifest/uap/windows10/5\" xmlns:desktop6=\"http://schemas.microsoft.com/appx/manifest/desktop/windows10/6\" IgnorableNamespaces=\"rescap uap uap3 uap5 desktop6\">\n  <Identity Name=\"ohmyposh.cli\" Version=\"28.0.0.0\" Publisher=\"CN=Jan Joris De Dobbeleer, O=Jan Joris De Dobbeleer, L=Diest, C=BE\" ProcessorArchitecture=\"arm64\" />\n  <Properties>\n    <DisplayName>Oh My Posh</DisplayName>\n    <PublisherDisplayName>Jan Joris De Dobbeleer</PublisherDisplayName>\n    <Description>A prompt theme engine for any shell.</Description>\n    <Logo>icons\\icon.png</Logo>\n    <desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>\n  </Properties>\n  <Resources>\n    <Resource Language=\"en-us\" />\n  </Resources>\n  <Dependencies>\n    <TargetDeviceFamily Name=\"Windows.Desktop\" MinVersion=\"10.0.17134.0\" MaxVersionTested=\"10.0.22631.0\" />\n  </Dependencies>\n  <Capabilities>\n    <rescap:Capability Name=\"runFullTrust\" />\n    <rescap:Capability Name=\"unvirtualizedResources\" />\n  </Capabilities>\n  <Applications>\n    <Application Id=\"OhMyPosh\" Executable=\"oh-my-posh.exe\" EntryPoint=\"Windows.FullTrustApplication\">\n      <uap3:VisualElements DisplayName=\"Oh My Posh\" Description=\"Oh My Posh CLI\" Square150x150Logo=\"icons\\icon.png\" Square44x44Logo=\"icons\\44.png\" BackgroundColor=\"#373e5f\" AppListEntry=\"default\" VisualGroup=\"Oh My Posh\">\n      </uap3:VisualElements>\n      <Extensions>\n        <uap5:Extension Category=\"windows.appExecutionAlias\">\n          <uap5:AppExecutionAlias>\n            <uap5:ExecutionAlias Alias=\"oh-my-posh.exe\" />\n          </uap5:AppExecutionAlias>\n        </uap5:Extension>\n      </Extensions>\n    </Application>\n  </Applications>\n</Package>"
  },
  {
    "path": "packages/msi/build.ps1",
    "content": "<#\n.SYNOPSIS\n    Builds MSI and MSIX packages for Oh My Posh.\n\n.DESCRIPTION\n    This script creates MSI and MSIX installer packages for Oh My Posh with the specified architecture and version.\n    It can optionally copy the executable, sign the packages, and generate hash files for verification.\n\n.PARAMETER Architecture\n    The target architecture for the package. Must be either 'x64' or 'arm64'.\n\n.PARAMETER Version\n    The version number to assign to the package (e.g., \"1.2.3\").\n\n.PARAMETER SDKVersion\n    The Windows SDK version to use for signing and packaging tools. Defaults to \"10.0.26100.0\".\n\n.PARAMETER Sign\n    When specified, signs the MSI and MSIX packages using Azure Code Signing.\n\n.PARAMETER Copy\n    When specified, copies the appropriate executable from the dist folder before packaging.\n\n.EXAMPLE\n    .\\build.ps1 -Architecture x64 -Version \"1.2.3\" -Copy\n\n    Creates MSI and MSIX packages for x64 architecture with version 1.2.3, copying the executable first.\n\n.EXAMPLE\n    .\\build.ps1 -Architecture arm64 -Version \"1.2.3\" -Sign -Copy\n\n    Creates and signs MSI and MSIX packages for arm64 architecture with version 1.2.3.\n\n.OUTPUTS\n    Creates the following files in the 'out' directory:\n    - install-{Architecture}.msi\n    - install-{Architecture}.msix\n    - Hash files (.sha256) for verification\n\n.NOTES\n    Requires WiX toolset for MSI creation and Windows SDK for MSIX packaging and signing.\n#>\n\n[CmdletBinding()]\nparam(\n    [Parameter(Mandatory = $true)]\n    [ValidateSet('x64', 'arm64')]\n    [string]$Architecture,\n\n    [Parameter(Mandatory = $true)]\n    [ValidateNotNullOrEmpty()]\n    [string]$Version,\n\n    [Parameter()]\n    [ValidateNotNullOrEmpty()]\n    [string]$SDKVersion = \"10.0.26100.0\",\n\n    [Parameter()]\n    [switch]$Sign,\n\n    [Parameter()]\n    [switch]$Copy\n)\n\n# Set error handling preferences\n$ErrorActionPreference = 'Stop'\n$PSNativeCommandUseErrorActionPreference = $true\n$PSDefaultParameterValues['Out-File:Encoding'] = 'UTF8'\n\n#region Helper Functions\n\nfunction Initialize-SigningEnvironment {\n    <#\n    .SYNOPSIS\n        Sets up the signing environment and returns signing tool paths.\n\n    .PARAMETER SDKVersion\n        The Windows SDK version to use.\n\n    .OUTPUTS\n        Hashtable containing signtool and signtoolDlib paths.\n    #>\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [string]$SDKVersion\n    )\n\n    try {\n        Write-Verbose \"Setting up signing environment\" -Verbose\n\n        # Install Microsoft.Trusted.Signing.Client\n        nuget.exe install Microsoft.Trusted.Signing.Client -Version 1.0.92 -x | Out-Null\n\n        $signtoolDlib = \"$PWD/Microsoft.Trusted.Signing.Client/bin/x64/Azure.CodeSigning.Dlib.dll\" -replace '\\\\', '/'\n        $signtool = \"C:/Program Files (x86)/Windows Kits/10/bin/$SDKVersion/x64/signtool.exe\" -replace '\\\\', '/'\n\n        # Validate tools exist\n        if (-not (Test-Path $signtool)) {\n            throw \"signtool.exe not found at: $signtool\"\n        }\n        if (-not (Test-Path $signtoolDlib)) {\n            throw \"Azure.CodeSigning.Dlib.dll not found at: $signtoolDlib\"\n        }\n\n        # Explicitly create and return a hashtable\n        [hashtable]$result = @{\n            SignTool = $signtool\n            SignToolDlib = $signtoolDlib\n        }\n\n        return $result\n    }\n    catch {\n        Write-Error \"Failed to initialize signing environment: $_\"\n        throw\n    }\n}\n\nfunction Invoke-PackageSigning {\n    <#\n    .SYNOPSIS\n        Signs a package using Azure Code Signing.\n\n    .PARAMETER PackagePath\n        The path to the package to sign.\n\n    .PARAMETER SigningTools\n        Hashtable containing signing tool paths from Initialize-SigningEnvironment.\n    #>\n    [CmdletBinding()]\n    param(\n        [Parameter(Mandatory = $true)]\n        [ValidateScript({Test-Path $_})]\n        [string]$PackagePath,\n\n        [Parameter(Mandatory = $true)]\n        [hashtable]$SigningTools\n    )\n\n    try {\n        $packageName = Split-Path $PackagePath -Leaf\n        Write-Verbose \"Signing package: $packageName\" -Verbose\n\n        & $SigningTools.SignTool sign /v /debug /d \"Oh My Posh\" /fd SHA256 /tr 'http://timestamp.acs.microsoft.com' /td SHA256 /dlib $SigningTools.SignToolDlib /dmdf ../../src/metadata.json $PackagePath\n\n        Write-Verbose \"Successfully signed: $packageName\" -Verbose\n    }\n    catch {\n        Write-Error \"Failed to sign package ${PackagePath}: ${_}\"\n        throw\n    }\n}\n\n#endregion\n\n#region Main Script\n\nWrite-Verbose \"Building MSI for $Architecture with version $Version\" -Verbose\nWrite-Verbose \"Setting up output directories\" -Verbose\n\ntry {\n    New-Item -Path \".\" -Name \"dist\" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null\n    New-Item -Path \".\" -Name \"out\" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null\n}\ncatch {\n    Write-Error \"Failed to create output directories: ${_}\"\n    throw\n}\n\nif ($Copy) {\n    $sourceFile = switch ($Architecture) {\n        'x64' { \"posh-windows-amd64.exe\" }\n        Default { \"posh-windows-$Architecture.exe\" }\n    }\n\n    Write-Verbose \"Copying $sourceFile to ./dist/oh-my-posh.exe\" -Verbose\n\n    try {\n        $sourcePath = \"../../dist/$sourceFile\"\n        if (-not (Test-Path $sourcePath)) {\n            throw \"Source file not found: $sourcePath\"\n        }\n        Copy-Item -Path $sourcePath -Destination \"./dist/oh-my-posh.exe\" -Force\n    }\n    catch {\n        Write-Error \"Failed to copy executable: $_\"\n        throw\n    }\n}\n\n# Set version environment variable for WiX\n$env:VERSION = $Version\n\nWrite-Verbose \"Creating MSI package\" -Verbose\n\ntry {\n    # Define MSI package paths\n    $msiFileName = \"install-$Architecture.msi\"\n    $msiPackagePath = \"$PWD/out/$msiFileName\" -replace '\\\\', '/'\n\n    Write-Verbose \"Building MSI: $msiPackagePath\" -Verbose\n    wix build -arch $Architecture -out $msiPackagePath .\\oh-my-posh.wxs\n\n    if (-not (Test-Path $msiPackagePath)) {\n        throw \"MSI package was not created successfully\"\n    }\n}\ncatch {\n    Write-Error \"Failed to create MSI package: ${_}\"\n    throw\n}\n\nif ($Sign) {\n    $signingTools = Initialize-SigningEnvironment -SDKVersion $SDKVersion\n    Invoke-PackageSigning -PackagePath $msiPackagePath -SigningTools $signingTools\n}\n\nWrite-Verbose \"Creating MSIX package\" -Verbose\n\ntry {\n    # Define MSIX package paths and files\n    $currentPath = $PWD -replace '\\\\', '/'\n    $manifestPath = \"$currentPath/appxmanifest.xml\"\n    $mappingFilePath = \"$currentPath/mapping.txt\"\n    $msixPackagePath = \"$currentPath/out/$($msiFileName)x\"\n    $makeappxPath = \"C:/Program Files (x86)/Windows Kits/10/bin/$SDKVersion/x64/makeappx.exe\"\n\n    # Validate required files exist\n    if (-not (Test-Path $manifestPath)) {\n        throw \"Manifest file not found: $manifestPath\"\n    }\n    if (-not (Test-Path $mappingFilePath)) {\n        throw \"Mapping file not found: $mappingFilePath\"\n    }\n    if (-not (Test-Path $makeappxPath)) {\n        throw \"makeappx.exe not found at: $makeappxPath\"\n    }\n\n    # Update manifest with version and architecture\n    [xml]$manifestDocument = Get-Content $manifestPath\n    $manifestDocument.Package.Identity.Version = \"$Version.0\"\n    $manifestDocument.Package.Identity.ProcessorArchitecture = $Architecture\n    $manifestDocument.Save($manifestPath)\n\n    # Build MSIX package\n    Write-Verbose \"Building MSIX: $msixPackagePath\" -Verbose\n    & \"$makeappxPath\" pack /p $msixPackagePath /v /o /m $manifestPath /f $mappingFilePath\n\n    if (-not (Test-Path $msixPackagePath)) {\n        throw \"MSIX package was not created successfully\"\n    }\n}\ncatch {\n    Write-Error \"Failed to create MSIX package: ${_}\"\n    throw\n}\n\nif ($Sign) {\n    if ($null -eq $signingTools) {\n        $signingTools = Initialize-SigningEnvironment -SDKVersion $SDKVersion\n    }\n    Invoke-PackageSigning -PackagePath $msixPackagePath -SigningTools $signingTools\n}\n\nWrite-Verbose \"Successfully completed building MSI and MSIX packages\" -Verbose\n\n#endregion\n"
  },
  {
    "path": "packages/msi/dsc/oh-my-posh.config.dsc.resource.json",
    "content": "{\n  \"$schema\": \"https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json\",\n  \"description\": \"Allows configuring the Oh My Posh config files.\",\n  \"export\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"config\",\n      \"dsc\",\n      \"export\"\n    ]\n  },\n  \"get\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"config\",\n      \"dsc\",\n      \"get\"\n    ]\n  },\n  \"schema\": {\n    \"command\": {\n      \"executable\": \"oh-my-posh\",\n      \"args\": [\n        \"config\",\n        \"dsc\",\n        \"schema\"\n      ]\n    }\n  },\n  \"set\": {\n    \"executable\": \"oh-my-posh\",\n    \"implementsPretest\": true,\n    \"args\": [\n      \"config\",\n      \"dsc\",\n      \"set\",\n      {\n        \"jsonInputArg\": \"--state\",\n        \"mandatory\": true\n      }\n    ]\n  },\n  \"tags\": [\n    \"OhMyPosh\",\n    \"linux\",\n    \"macos\",\n    \"windows\",\n    \"shell\",\n    \"powershell\",\n    \"terminal\",\n    \"theming\",\n    \"configuration\"\n  ],\n  \"type\": \"OhMyPosh/Config\",\n  \"version\": \"0.1.0\"\n}\n"
  },
  {
    "path": "packages/msi/dsc/oh-my-posh.font.dsc.resource.json",
    "content": "{\n  \"$schema\": \"https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json\",\n  \"description\": \"Allows configuring the Oh My Posh font installs.\",\n  \"export\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"font\",\n      \"dsc\",\n      \"export\"\n    ]\n  },\n  \"get\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"font\",\n      \"dsc\",\n      \"get\"\n    ]\n  },\n  \"schema\": {\n    \"command\": {\n      \"executable\": \"oh-my-posh\",\n      \"args\": [\n        \"font\",\n        \"dsc\",\n        \"schema\"\n      ]\n    }\n  },\n  \"set\": {\n    \"executable\": \"oh-my-posh\",\n    \"implementsPretest\": true,\n    \"args\": [\n      \"font\",\n      \"dsc\",\n      \"set\",\n      {\n        \"jsonInputArg\": \"--state\",\n        \"mandatory\": true\n      }\n    ]\n  },\n  \"tags\": [\n    \"OhMyPosh\",\n    \"linux\",\n    \"macos\",\n    \"windows\",\n    \"powershell\",\n    \"terminal\",\n    \"theming\",\n    \"fonts\"\n  ],\n  \"type\": \"OhMyPosh/Font\",\n  \"version\": \"0.1.0\"\n}\n"
  },
  {
    "path": "packages/msi/dsc/oh-my-posh.shell.dsc.resource.json",
    "content": "{\n  \"$schema\": \"https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.vscode.json\",\n  \"description\": \"Allows configuring the Oh My Posh shell integration.\",\n  \"export\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"shell\",\n      \"dsc\",\n      \"export\"\n    ]\n  },\n  \"get\": {\n    \"executable\": \"oh-my-posh\",\n    \"input\": \"stdin\",\n    \"args\": [\n      \"shell\",\n      \"dsc\",\n      \"get\"\n    ]\n  },\n  \"schema\": {\n    \"command\": {\n      \"executable\": \"oh-my-posh\",\n      \"args\": [\n        \"shell\",\n        \"dsc\",\n        \"schema\"\n      ]\n    }\n  },\n  \"set\": {\n    \"executable\": \"oh-my-posh\",\n    \"implementsPretest\": true,\n    \"args\": [\n      \"shell\",\n      \"dsc\",\n      \"set\",\n      {\n        \"jsonInputArg\": \"--state\",\n        \"mandatory\": true\n      }\n    ]\n  },\n  \"tags\": [\n    \"OhMyPosh\",\n    \"linux\",\n    \"macos\",\n    \"windows\",\n    \"shell\",\n    \"powershell\",\n    \"terminal\",\n    \"theming\"\n  ],\n  \"type\": \"OhMyPosh/Shell\",\n  \"version\": \"0.1.0\"\n}\n"
  },
  {
    "path": "packages/msi/mapping.txt",
    "content": "[ResourceMetadata]\n\"ResourceDimensions\"                    \"language-en-us\"\n\"ResourceId\"                            \"English\"\n\n[Files]\n\"./dist/oh-my-posh.exe\" \"oh-my-posh.exe\"\n\"./icons/icon.png\" \"/icons/icon.png\"\n\"./icons/44.png\" \"/icons/44.png\"\n\"./dsc/oh-my-posh.config.dsc.resource.json\" \"oh-my-posh.config.dsc.resource.json\"\n\"./dsc/oh-my-posh.shell.dsc.resource.json\" \"oh-my-posh.shell.dsc.resource.json\"\n\"./dsc/oh-my-posh.font.dsc.resource.json\" \"oh-my-posh.font.dsc.resource.json\"\n\"../../themes/1_shell.omp.json\" \"/themes/1_shell.omp.json\"\n\"../../themes/agnoster.minimal.omp.json\" \"/themes/agnoster.minimal.omp.json\"\n\"../../themes/agnoster.omp.json\" \"/themes/agnoster.omp.json\"\n\"../../themes/agnosterplus.omp.json\" \"/themes/agnosterplus.omp.json\"\n\"../../themes/aliens.omp.json\" \"/themes/aliens.omp.json\"\n\"../../themes/amro.omp.json\" \"/themes/amro.omp.json\"\n\"../../themes/atomic.omp.json\" \"/themes/atomic.omp.json\"\n\"../../themes/atomicBit.omp.json\" \"/themes/atomicBit.omp.json\"\n\"../../themes/avit.omp.json\" \"/themes/avit.omp.json\"\n\"../../themes/blue-owl.omp.json\" \"/themes/blue-owl.omp.json\"\n\"../../themes/blueish.omp.json\" \"/themes/blueish.omp.json\"\n\"../../themes/bubbles.omp.json\" \"/themes/bubbles.omp.json\"\n\"../../themes/bubblesextra.omp.json\" \"/themes/bubblesextra.omp.json\"\n\"../../themes/bubblesline.omp.json\" \"/themes/bubblesline.omp.json\"\n\"../../themes/capr4n.omp.json\" \"/themes/capr4n.omp.json\"\n\"../../themes/catppuccin.omp.json\" \"/themes/catppuccin.omp.json\"\n\"../../themes/catppuccin_frappe.omp.json\" \"/themes/catppuccin_frappe.omp.json\"\n\"../../themes/catppuccin_latte.omp.json\" \"/themes/catppuccin_latte.omp.json\"\n\"../../themes/catppuccin_macchiato.omp.json\" \"/themes/catppuccin_macchiato.omp.json\"\n\"../../themes/catppuccin_mocha.omp.json\" \"/themes/catppuccin_mocha.omp.json\"\n\"../../themes/cert.omp.json\" \"/themes/cert.omp.json\"\n\"../../themes/chips.omp.json\" \"/themes/chips.omp.json\"\n\"../../themes/cinnamon.omp.json\" \"/themes/cinnamon.omp.json\"\n\"../../themes/clean-detailed.omp.json\" \"/themes/clean-detailed.omp.json\"\n\"../../themes/cloud-context.omp.json\" \"/themes/cloud-context.omp.json\"\n\"../../themes/cloud-native-azure.omp.json\" \"/themes/cloud-native-azure.omp.json\"\n\"../../themes/cobalt2.omp.json\" \"/themes/cobalt2.omp.json\"\n\"../../themes/craver.omp.json\" \"/themes/craver.omp.json\"\n\"../../themes/darkblood.omp.json\" \"/themes/darkblood.omp.json\"\n\"../../themes/devious-diamonds.omp.yaml\" \"/themes/devious-diamonds.omp.yaml\"\n\"../../themes/di4am0nd.omp.json\" \"/themes/di4am0nd.omp.json\"\n\"../../themes/dracula.omp.json\" \"/themes/dracula.omp.json\"\n\"../../themes/easy-term.omp.json\" \"/themes/easy-term.omp.json\"\n\"../../themes/emodipt-extend.omp.json\" \"/themes/emodipt-extend.omp.json\"\n\"../../themes/emodipt.omp.json\" \"/themes/emodipt.omp.json\"\n\"../../themes/fish.omp.json\" \"/themes/fish.omp.json\"\n\"../../themes/free-ukraine.omp.json\" \"/themes/free-ukraine.omp.json\"\n\"../../themes/froczh.omp.json\" \"/themes/froczh.omp.json\"\n\"../../themes/glowsticks.omp.yaml\" \"/themes/glowsticks.omp.yaml\"\n\"../../themes/gmay.omp.json\" \"/themes/gmay.omp.json\"\n\"../../themes/grandpa-style.omp.json\" \"/themes/grandpa-style.omp.json\"\n\"../../themes/gruvbox.omp.json\" \"/themes/gruvbox.omp.json\"\n\"../../themes/half-life.omp.json\" \"/themes/half-life.omp.json\"\n\"../../themes/honukai.omp.json\" \"/themes/honukai.omp.json\"\n\"../../themes/hotstick.minimal.omp.json\" \"/themes/hotstick.minimal.omp.json\"\n\"../../themes/hul10.omp.json\" \"/themes/hul10.omp.json\"\n\"../../themes/hunk.omp.json\" \"/themes/hunk.omp.json\"\n\"../../themes/huvix.omp.json\" \"/themes/huvix.omp.json\"\n\"../../themes/if_tea.omp.json\" \"/themes/if_tea.omp.json\"\n\"../../themes/illusi0n.omp.json\" \"/themes/illusi0n.omp.json\"\n\"../../themes/iterm2.omp.json\" \"/themes/iterm2.omp.json\"\n\"../../themes/jandedobbeleer.omp.json\" \"/themes/jandedobbeleer.omp.json\"\n\"../../themes/jblab_2021.omp.json\" \"/themes/jblab_2021.omp.json\"\n\"../../themes/jonnychipz.omp.json\" \"/themes/jonnychipz.omp.json\"\n\"../../themes/json.omp.json\" \"/themes/json.omp.json\"\n\"../../themes/jtracey93.omp.json\" \"/themes/jtracey93.omp.json\"\n\"../../themes/jv_sitecorian.omp.json\" \"/themes/jv_sitecorian.omp.json\"\n\"../../themes/kali.omp.json\" \"/themes/kali.omp.json\"\n\"../../themes/kushal.omp.json\" \"/themes/kushal.omp.json\"\n\"../../themes/lambda.omp.json\" \"/themes/lambda.omp.json\"\n\"../../themes/lambdageneration.omp.json\" \"/themes/lambdageneration.omp.json\"\n\"../../themes/larserikfinholt.omp.json\" \"/themes/larserikfinholt.omp.json\"\n\"../../themes/lightgreen.omp.json\" \"/themes/lightgreen.omp.json\"\n\"../../themes/M365Princess.omp.json\" \"/themes/M365Princess.omp.json\"\n\"../../themes/marcduiker.omp.json\" \"/themes/marcduiker.omp.json\"\n\"../../themes/markbull.omp.json\" \"/themes/markbull.omp.json\"\n\"../../themes/material.omp.json\" \"/themes/material.omp.json\"\n\"../../themes/microverse-power.omp.json\" \"/themes/microverse-power.omp.json\"\n\"../../themes/mojada.omp.json\" \"/themes/mojada.omp.json\"\n\"../../themes/montys.omp.json\" \"/themes/montys.omp.json\"\n\"../../themes/mt.omp.json\" \"/themes/mt.omp.json\"\n\"../../themes/multiverse-neon.omp.json\" \"/themes/multiverse-neon.omp.json\"\n\"../../themes/negligible.omp.json\" \"/themes/negligible.omp.json\"\n\"../../themes/neko.omp.json\" \"/themes/neko.omp.json\"\n\"../../themes/night-owl.omp.json\" \"/themes/night-owl.omp.json\"\n\"../../themes/nordtron.omp.json\" \"/themes/nordtron.omp.json\"\n\"../../themes/nu4a.omp.json\" \"/themes/nu4a.omp.json\"\n\"../../themes/onehalf.minimal.omp.json\" \"/themes/onehalf.minimal.omp.json\"\n\"../../themes/paradox.omp.json\" \"/themes/paradox.omp.json\"\n\"../../themes/pararussel.omp.json\" \"/themes/pararussel.omp.json\"\n\"../../themes/patriksvensson.omp.json\" \"/themes/patriksvensson.omp.json\"\n\"../../themes/peru.omp.json\" \"/themes/peru.omp.json\"\n\"../../themes/pixelrobots.omp.json\" \"/themes/pixelrobots.omp.json\"\n\"../../themes/plague.omp.json\" \"/themes/plague.omp.json\"\n\"../../themes/poshmon.omp.json\" \"/themes/poshmon.omp.json\"\n\"../../themes/powerlevel10k_classic.omp.json\" \"/themes/powerlevel10k_classic.omp.json\"\n\"../../themes/powerlevel10k_lean.omp.json\" \"/themes/powerlevel10k_lean.omp.json\"\n\"../../themes/powerlevel10k_modern.omp.json\" \"/themes/powerlevel10k_modern.omp.json\"\n\"../../themes/powerlevel10k_rainbow.omp.json\" \"/themes/powerlevel10k_rainbow.omp.json\"\n\"../../themes/powerline.omp.json\" \"/themes/powerline.omp.json\"\n\"../../themes/probua.minimal.omp.json\" \"/themes/probua.minimal.omp.json\"\n\"../../themes/pure.omp.json\" \"/themes/pure.omp.json\"\n\"../../themes/quick-term.omp.json\" \"/themes/quick-term.omp.json\"\n\"../../themes/remk.omp.json\" \"/themes/remk.omp.json\"\n\"../../themes/robbyrussell.omp.json\" \"/themes/robbyrussell.omp.json\"\n\"../../themes/rudolfs-dark.omp.json\" \"/themes/rudolfs-dark.omp.json\"\n\"../../themes/rudolfs-light.omp.json\" \"/themes/rudolfs-light.omp.json\"\n\"../../themes/sim-web.omp.json\" \"/themes/sim-web.omp.json\"\n\"../../themes/slim.omp.json\" \"/themes/slim.omp.json\"\n\"../../themes/slimfat.omp.json\" \"/themes/slimfat.omp.json\"\n\"../../themes/smoothie.omp.json\" \"/themes/smoothie.omp.json\"\n\"../../themes/sonicboom_dark.omp.json\" \"/themes/sonicboom_dark.omp.json\"\n\"../../themes/sonicboom_light.omp.json\" \"/themes/sonicboom_light.omp.json\"\n\"../../themes/sorin.omp.json\" \"/themes/sorin.omp.json\"\n\"../../themes/space.omp.json\" \"/themes/space.omp.json\"\n\"../../themes/spaceship.omp.json\" \"/themes/spaceship.omp.json\"\n\"../../themes/star.omp.json\" \"/themes/star.omp.json\"\n\"../../themes/stelbent-compact.minimal.omp.json\" \"/themes/stelbent-compact.minimal.omp.json\"\n\"../../themes/stelbent.minimal.omp.json\" \"/themes/stelbent.minimal.omp.json\"\n\"../../themes/takuya.omp.json\" \"/themes/takuya.omp.json\"\n\"../../themes/the-unnamed.omp.json\" \"/themes/the-unnamed.omp.json\"\n\"../../themes/thecyberden.omp.json\" \"/themes/thecyberden.omp.json\"\n\"../../themes/tiwahu.omp.json\" \"/themes/tiwahu.omp.json\"\n\"../../themes/tokyo.omp.json\" \"/themes/tokyo.omp.json\"\n\"../../themes/tokyonight_storm.omp.json\" \"/themes/tokyonight_storm.omp.json\"\n\"../../themes/tonybaloney.omp.json\" \"/themes/tonybaloney.omp.json\"\n\"../../themes/uew.omp.json\" \"/themes/uew.omp.json\"\n\"../../themes/unicorn.omp.json\" \"/themes/unicorn.omp.json\"\n\"../../themes/velvet.omp.json\" \"/themes/velvet.omp.json\"\n\"../../themes/wholespace.omp.json\" \"/themes/wholespace.omp.json\"\n\"../../themes/wopian.omp.json\" \"/themes/wopian.omp.json\"\n\"../../themes/xtoys.omp.json\" \"/themes/xtoys.omp.json\"\n\"../../themes/ys.omp.json\" \"/themes/ys.omp.json\"\n\"../../themes/zash.omp.json\" \"/themes/zash.omp.json\"\n"
  },
  {
    "path": "packages/msi/oh-my-posh.wxs",
    "content": "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">\n\t<Package Language=\"1033\" Manufacturer=\"Jan De Dobbeleer\" Name=\"Oh My Posh\" UpgradeCode=\"b2a6bcaa-bda3-4c7f-8dec-d8665d7a9b69\" Version=\"$(env.VERSION)\" Scope=\"perUserOrMachine\">\n\t\t<SummaryInformation Description=\"https://ohmyposh.dev\" />\n\t\t<Icon Id=\"icon.ico\" SourceFile=\"icon.ico\" />\n\t\t<Property Id=\"ARPPRODUCTICON\" Value=\"icon.ico\" />\n\t\t<Property Id=\"INSTALLER\" Value=\"manual\" />\n\t\t<MediaTemplate EmbedCab=\"yes\" />\n\t\t<StandardDirectory Id=\"ProgramFilesFolder\">\n\t\t\t<Directory Id=\"ParentInstallDir\" Name=\"oh-my-posh\">\n\t\t\t\t<Directory Id=\"INSTALLDIR\" Name=\"bin\" />\n\t\t\t\t<Directory Id=\"THEMESDIR\" Name=\"themes\" />\n\t\t\t</Directory>\n\t\t</StandardDirectory>\n\t\t<Feature Id=\"Installation\" AllowAbsent=\"no\" Description=\"https://ohmyposh.dev\" Title=\"Oh My Posh\">\n\t\t\t<ComponentGroupRef Id=\"Files\" />\n\t\t\t<ComponentGroupRef Id=\"EnvironmentVariables\" />\n\t\t</Feature>\n\t\t<InstallExecuteSequence>\n\t\t\t<RemoveExistingProducts After=\"InstallValidate\" />\n\t\t</InstallExecuteSequence>\n\t</Package>\n\t<Fragment>\n\t\t<ComponentGroup Id=\"Files\">\n\t\t\t<Component Id=\"Executable\" Directory=\"INSTALLDIR\">\n\t\t\t\t<File Source=\"dist/oh-my-posh.exe\" />\n\t\t\t</Component>\n\t\t\t<Files Directory=\"THEMESDIR\" Include=\"../../themes/*.omp.*\" />\n\t\t</ComponentGroup>\n\t</Fragment>\n\t<Fragment>\n\t\t<ComponentGroup Id=\"EnvironmentVariables\">\n\t\t\t<Component Id=\"SystemEnvironmentVariables\" Condition=\"ALLUSERS=1\" Directory=\"INSTALLDIR\" Guid=\"ee903196-9032-4592-b461-25c96823bed7\">\n\t\t\t\t<Environment Id=\"SystemPath\" Action=\"set\" Name=\"Path\" Part=\"first\" Permanent=\"no\" System=\"yes\" Value=\"[INSTALLDIR]\" />\n\t\t\t\t<Environment Id=\"SystemThemesDir\" Action=\"set\" Name=\"POSH_THEMES_PATH\" Part=\"all\" Permanent=\"no\" System=\"yes\" Value=\"[THEMESDIR]\" />\n\t\t\t\t<Environment Id=\"SystemInstaller\" Action=\"set\" Name=\"POSH_INSTALLER\" Part=\"all\" Permanent=\"no\" System=\"yes\" Value=\"[INSTALLER]\" />\n\t\t\t</Component>\n\t\t\t<Component Id=\"UserEnvironmentVariables\" Condition=\"NOT ALLUSERS\" Directory=\"INSTALLDIR\" Guid=\"212dc904-b134-45b6-a647-a05ce417684a\">\n\t\t\t\t<Environment Id=\"UserPath\" Action=\"set\" Name=\"Path\" Part=\"first\" Permanent=\"no\" System=\"no\" Value=\"[INSTALLDIR]\" />\n\t\t\t\t<Environment Id=\"UserThemesDir\" Action=\"set\" Name=\"POSH_THEMES_PATH\" Part=\"all\" Permanent=\"no\" System=\"no\" Value=\"[THEMESDIR]\" />\n\t\t\t\t<Environment Id=\"UserInstaller\" Action=\"set\" Name=\"POSH_INSTALLER\" Part=\"all\" Permanent=\"no\" System=\"no\" Value=\"[INSTALLER]\" />\n\t\t\t</Component>\n\t\t</ComponentGroup>\n\t</Fragment>\n</Wix>\n"
  },
  {
    "path": "src/.golangci.yml",
    "content": "version: \"2\"\nrun:\n  allow-parallel-runners: true\nlinters:\n  default: none\n  enable:\n    - bodyclose\n    - copyloopvar\n    - dupl\n    - errcheck\n    - exhaustive\n    - goconst\n    - gocritic\n    - gocyclo\n    - goprintffuncname\n    - govet\n    - ineffassign\n    - lll\n    - misspell\n    - nakedret\n    - noctx\n    - nolintlint\n    - revive\n    - rowserrcheck\n    - staticcheck\n    - unconvert\n    - unparam\n    - unused\n    - whitespace\n  settings:\n    gocritic:\n      enabled-tags:\n        - diagnostic\n        - opinionated\n        - performance\n        - style\n      disabled-tags:\n        - experimental\n    lll:\n      line-length: 180\n    revive:\n      rules:\n        - name: var-naming\n          disabled: true\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\nformatters:\n  enable:\n    - gofmt\n    - goimports\n  exclusions:\n    generated: lax\n    paths:\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": "src/.goreleaser.yml",
    "content": "# Make sure to check the documentation at https://goreleaser.com\n# yaml-language-server: $schema=https://goreleaser.com/static/schema.json\nversion: 2\nbefore:\n  hooks:\n    - go mod tidy\n    - go install github.com/tc-hib/go-winres@latest\n    - go-winres make --product-version=git-tag --file-version=git-tag --arch=\"amd64,arm64\"\nbuilds:\n  -\n    binary: \"posh-{{ .Os }}-{{ .Arch }}\"\n    no_unique_dist_dir: true\n    flags:\n      - -a\n    ldflags:\n      - -s -w\n      - -X github.com/jandedobbeleer/oh-my-posh/src/build.Version={{ .Version }}\n      - -X github.com/jandedobbeleer/oh-my-posh/src/build.Date={{ .Date }}\n      - -extldflags \"-static\"\n    tags:\n      - netgo\n      - osusergo\n      - static_build\n      - timetzdata\n    env:\n      - CGO_ENABLED=0\n      - GOEXPERIMENT=greenteagc,jsonv2\n    goos:\n      - linux\n      - windows\n      - darwin\n      - freebsd\n    goarch:\n      - amd64\n      - arm64\n      - arm\n    ignore:\n      - goos: darwin\n        goarch: arm\n      - goos: windows\n        goarch: arm\n    hooks:\n      post:\n        - pwsh -c \"if ('{{ .Path }}'.EndsWith('.exe')) { & '{{ .Env.SIGNTOOL }}' sign /v /debug /fd SHA256 /tr 'http://timestamp.acs.microsoft.com' /td SHA256 /dlib '{{ .Env.SIGNTOOLDLIB }}' /dmdf './metadata.json' '{{ .Path }}' }\"\narchives:\n  - id: oh-my-posh\n    format: binary\n    name_template: \"posh-{{ .Os }}-{{ .Arch }}\"\nchecksum:\n  name_template: 'checksums.txt'\nsigns:\n  - cmd: pwsh\n    args:\n      - \"-c\"\n      - \"& '{{ .Env.OPENSSL }}' pkeyutl -sign -inkey '{{ .Env.SHA_SIGNING_KEY_LOCATION }}' -out '${artifact}.sig' -rawin -in '${artifact}'\"\n    artifacts: checksum\nchangelog:\n  disable: true\n"
  },
  {
    "path": "src/build/version.go",
    "content": "package build\n\nvar (\n\tDate    string\n\tVersion = \"0.0.0-dev\"\n)\n"
  },
  {
    "path": "src/cache/cache.go",
    "content": "package cache\n\nimport (\n\t\"encoding/gob\"\n\t\"time\"\n)\n\nfunc init() {\n\tgob.Register(&Entry[any]{})\n\tgob.Register(Template{})\n\tgob.Register(SimpleTemplate{})\n\tgob.Register((*Duration)(nil))\n\tgob.Register(map[string]bool{})\n}\n\nconst (\n\tDeviceStore = \"omp.cache\"\n)\n\nconst (\n\tTEMPLATECACHE    = \"template_cache\"\n\tTOGGLECACHE      = \"toggle_cache\"\n\tPROMPTCOUNTCACHE = \"prompt_count_cache\"\n\tENGINECACHE      = \"engine_cache\"\n\tFONTLISTCACHE    = \"font_list_cache\"\n\tCLAUDECACHE      = \"claude_cache\"\n)\n\ntype Entry[T any] struct {\n\tValue     T\n\tTimestamp int64\n\tTTL       int\n}\n\nfunc (c *Entry[T]) Expired() bool {\n\tif c.TTL < 0 {\n\t\treturn false\n\t}\n\n\treturn time.Now().Unix() >= (c.Timestamp + int64(c.TTL))\n}\n"
  },
  {
    "path": "src/cache/clear.go",
    "content": "package cache\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\n// Clear removes cache files from the cache directory.\n//\n// If force is true, the entire cache directory is removed.\n// If force is false, only cache files older than 7 days that match certain patterns are deleted.\n// The excludedFiles parameter allows you to specify file names that should not be deleted,\n// even if they would otherwise be eligible for removal.\nfunc Clear(force bool, excludedFiles ...string) error {\n\tdefer log.Trace(time.Now())\n\n\tif force {\n\t\treturn os.RemoveAll(Path())\n\t}\n\n\t// get all files in the cache directory that start with omp.cache and delete them\n\tfiles, err := os.ReadDir(Path())\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// get all log files as well\n\tif logFiles, err := os.ReadDir(filepath.Join(Path(), \"logs\")); err == nil {\n\t\tfiles = append(files, logFiles...)\n\t}\n\n\tshouldSkip := func(fileName string) bool {\n\t\tif slices.Contains(excludedFiles, fileName) {\n\t\t\treturn true\n\t\t}\n\n\t\treturn strings.EqualFold(fileName, DeviceStore) || strings.HasPrefix(fileName, \"init.\")\n\t}\n\n\tif len(excludedFiles) > 0 {\n\t\tlog.Debug(\"excluding files from deletion:\", strings.Join(excludedFiles, \", \"))\n\t}\n\n\tdeleteFile := func(file string) {\n\t\tpath := filepath.Join(Path(), file)\n\t\terr := os.Remove(path)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debugf(\"removed cache file: %s\", path)\n\t}\n\n\tcacheTTL := GetTTL()\n\n\tlog.Debugf(\"removing cache files older than %d days\", cacheTTL)\n\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif shouldSkip(file.Name()) {\n\t\t\tlog.Debug(\"skipping excluded file:\", file.Name())\n\t\t\tcontinue\n\t\t}\n\n\t\tcacheFileInfo, err := file.Info()\n\t\tif err != nil {\n\t\t\tlog.Debug(\"skipping file, cannot get info:\", file.Name())\n\t\t\tcontinue\n\t\t}\n\n\t\tif cacheFileInfo.ModTime().After(time.Now().AddDate(0, 0, -cacheTTL)) {\n\t\t\tlog.Debug(\"skipping recently used file:\", file.Name())\n\t\t\tcontinue\n\t\t}\n\n\t\tdeleteFile(file.Name())\n\t}\n\n\treturn nil\n}\n\nfunc GetTTL() int {\n\tcacheTTL, OK := Get[int](Device, TTL)\n\tif !OK || cacheTTL <= 0 {\n\t\tcacheTTL = 7\n\t}\n\n\treturn cacheTTL\n}\n"
  },
  {
    "path": "src/cache/command.go",
    "content": "package cache\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n)\n\ntype Command struct {\n\tCommands *maps.Concurrent[string]\n}\n\nfunc (c *Command) Set(command, path string) {\n\tc.Commands.Set(command, path)\n}\n\nfunc (c *Command) Get(command string) (string, bool) {\n\tcacheCommand, found := c.Commands.Get(command)\n\tif !found {\n\t\treturn \"\", false\n\t}\n\n\treturn cacheCommand, true\n}\n"
  },
  {
    "path": "src/cache/duration.go",
    "content": "package cache\n\nimport (\n\t\"time\"\n)\n\ntype Duration string\n\nconst (\n\tINFINITE = Duration(\"infinite\")\n\tNONE     = Duration(\"none\")\n\tONEWEEK  = Duration(\"168h\")\n\tONEDAY   = Duration(\"24h\")\n\tTWOYEARS = Duration(\"17520h\")\n)\n\nfunc (d Duration) Seconds() int {\n\tif d == NONE {\n\t\treturn 0\n\t}\n\n\tif d == INFINITE {\n\t\treturn -1\n\t}\n\n\tduration, err := time.ParseDuration(string(d))\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn int(duration.Seconds())\n}\n\nfunc (d Duration) IsEmpty() bool {\n\treturn d == \"\"\n}\n\nfunc ToDuration(seconds int) Duration {\n\tif seconds == 0 {\n\t\treturn \"\"\n\t}\n\n\tif seconds == -1 {\n\t\treturn INFINITE\n\t}\n\n\tduration := time.Duration(seconds) * time.Second\n\treturn Duration(duration.String())\n}\n"
  },
  {
    "path": "src/cache/duration_test.go",
    "content": "package cache\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSeconds(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tDuration Duration\n\t\tExpected int\n\t}{\n\t\t{\n\t\t\tCase:     \"2 seconds\",\n\t\t\tDuration: \"2s\",\n\t\t\tExpected: 2,\n\t\t},\n\t\t{\n\t\t\tCase:     \"1 minute\",\n\t\t\tDuration: \"1m\",\n\t\t\tExpected: 60,\n\t\t},\n\t\t{\n\t\t\tCase:     \"2 hours\",\n\t\t\tDuration: \"2h\",\n\t\t\tExpected: 7200,\n\t\t},\n\t\t{\n\t\t\tCase:     \"2 days\",\n\t\t\tDuration: \"48h\",\n\t\t\tExpected: 172800,\n\t\t},\n\t\t{\n\t\t\tCase:     \"invalid\",\n\t\t\tDuration: \"foo\",\n\t\t\tExpected: 0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"1 fortnight\",\n\t\t\tDuration: \"1fortnight\",\n\t\t\tExpected: 0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"infinite\",\n\t\t\tDuration: \"infinite\",\n\t\t\tExpected: -1,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tgot := tc.Duration.Seconds()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/cache/file_map_windows.go",
    "content": "package cache\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\n// Configuration constants\nconst (\n\tminStringSize = 50 * 1024        // 50KB minimum string size\n\tmaxStringSize = 10 * 1024 * 1024 // 10MB maximum string size\n)\n\n// Windows API constants\nconst (\n\tfileMapAllAccess    = 0x001f001f\n\tpageReadwrite       = 0x04\n\tgenericRead         = 0x80000000\n\tgenericWrite        = 0x40000000\n\tcreateAlways        = 2\n\topenExisting        = 3\n\tfileAttributeNormal = 0x80\n)\n\n// Windows API functions\nvar (\n\tkernel32           = syscall.NewLazyDLL(\"kernel32.dll\")\n\tcreateFileW        = kernel32.NewProc(\"CreateFileW\")\n\tcreateFileMappingW = kernel32.NewProc(\"CreateFileMappingW\")\n\tmapViewOfFile      = kernel32.NewProc(\"MapViewOfFile\")\n\tunmapViewOfFile    = kernel32.NewProc(\"UnmapViewOfFile\")\n\tcloseHandle        = kernel32.NewProc(\"CloseHandle\")\n\tsetFilePointer     = kernel32.NewProc(\"SetFilePointer\")\n\tsetEndOfFile       = kernel32.NewProc(\"SetEndOfFile\")\n\tgetFileSizeEx      = kernel32.NewProc(\"GetFileSizeEx\")\n)\n\n// PersistentSharedString represents a memory-mapped file for storing a single string\ntype PersistentSharedString struct {\n\tfilePath   string\n\tfileHandle uintptr\n\tmapHandle  uintptr\n\tdata       uintptr\n\tsize       int // Current allocated size\n}\n\nfunc createOrOpenPersistentString(filePath string) (*PersistentSharedString, error) {\n\treturn createOrOpenPersistentStringWithSize(filePath, minStringSize)\n}\n\nfunc createOrOpenPersistentStringWithSize(filePath string, requiredSize int) (*PersistentSharedString, error) {\n\t// Ensure size is within bounds\n\tif requiredSize < minStringSize {\n\t\trequiredSize = minStringSize\n\t}\n\tif requiredSize > maxStringSize {\n\t\treturn nil, fmt.Errorf(\"required size %d exceeds maximum %d\", requiredSize, maxStringSize)\n\t}\n\n\t// First, try to open existing file\n\tpss, err := openExistingFileWithSize(filePath, requiredSize)\n\tif err == nil {\n\t\treturn pss, nil\n\t}\n\n\t// File doesn't exist or too small, create new one with required size\n\treturn createNewFileWithSize(filePath, requiredSize)\n}\n\n// openExistingFileWithSize attempts to open an existing memory-mapped file\n// openExistingFileWithSize attempts to open an existing memory-mapped file\nfunc openExistingFileWithSize(filePath string, requiredSize int) (*PersistentSharedString, error) {\n\tfilePathPtr, err := syscall.UTF16PtrFromString(filePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert file path to UTF16: %v\", err)\n\t}\n\n\t// Try to open existing file\n\tfileHandle, _, _ := createFileW.Call(\n\t\tuintptr(unsafe.Pointer(filePathPtr)), // lpFileName\n\t\tgenericRead|genericWrite,             // dwDesiredAccess\n\t\t0,                                    // dwShareMode\n\t\t0,                                    // lpSecurityAttributes\n\t\topenExisting,                         // dwCreationDisposition\n\t\tfileAttributeNormal,                  // dwFlagsAndAttributes\n\t\t0,                                    // hTemplateFile\n\t)\n\n\tif fileHandle == uintptr(0xFFFFFFFFFFFFFFFF) { // INVALID_HANDLE_VALUE\n\t\treturn nil, fmt.Errorf(\"file does not exist\")\n\t}\n\n\t// Get file size to check if it's large enough\n\tvar fileSize int64\n\tret, _, _ := getFileSizeEx.Call(fileHandle, uintptr(unsafe.Pointer(&fileSize)))\n\tif ret == 0 {\n\t\t_, _, _ = closeHandle.Call(fileHandle)\n\t\treturn nil, fmt.Errorf(\"failed to get file size\")\n\t}\n\n\tactualSize := int(fileSize) - 5 // Subtract header (4 bytes length + 1 null terminator)\n\tif actualSize < requiredSize {\n\t\t// Existing file is too small, close and recreate\n\t\t_, _, _ = closeHandle.Call(fileHandle)\n\t\treturn nil, fmt.Errorf(\"existing file is too small (%d < %d)\", actualSize, requiredSize)\n\t}\n\n\treturn createMappingFromFileWithSize(filePath, fileHandle, actualSize)\n}\n\n// createNewFileWithSize creates a new memory-mapped file with the specified size\nfunc createNewFileWithSize(filePath string, size int) (*PersistentSharedString, error) {\n\tfilePathPtr, err := syscall.UTF16PtrFromString(filePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to convert file path to UTF16: %v\", err)\n\t}\n\n\t// Create new file\n\tfileHandle, _, err := createFileW.Call(\n\t\tuintptr(unsafe.Pointer(filePathPtr)), // lpFileName\n\t\tgenericRead|genericWrite,             // dwDesiredAccess\n\t\t0,                                    // dwShareMode\n\t\t0,                                    // lpSecurityAttributes\n\t\tcreateAlways,                         // dwCreationDisposition (overwrites if exists)\n\t\tfileAttributeNormal,                  // dwFlagsAndAttributes\n\t\t0,                                    // hTemplateFile\n\t)\n\n\tif fileHandle == uintptr(0xFFFFFFFFFFFFFFFF) { // INVALID_HANDLE_VALUE\n\t\treturn nil, fmt.Errorf(\"CreateFileW failed: %v\", err)\n\t}\n\n\t// Set file size (4 bytes for length + size for string + 1 for null terminator)\n\ttotalSize := size + 5\n\t_, _, _ = setFilePointer.Call(fileHandle, uintptr(totalSize), 0, 0) // FILE_BEGIN = 0\n\t_, _, _ = setEndOfFile.Call(fileHandle)\n\n\tpss, mapErr := createMappingFromFileWithSize(filePath, fileHandle, size)\n\tif mapErr != nil {\n\t\t_, _, _ = closeHandle.Call(fileHandle)\n\t\treturn nil, mapErr\n\t}\n\n\t// Initialize new file with empty string\n\tbasePtr := unsafe.Pointer(pss.data)\n\tlengthPtr := (*uint32)(basePtr)\n\t*lengthPtr = 0\n\n\treturn pss, nil\n}\n\n// createMappingFromFileWithSize creates a memory mapping from an open file handle with specified size\nfunc createMappingFromFileWithSize(filePath string, fileHandle uintptr, size int) (*PersistentSharedString, error) {\n\ttotalSize := size + 5 // 4 bytes length + size + 1 null terminator\n\n\t// Create file mapping\n\tmapHandle, _, err := createFileMappingW.Call(\n\t\tfileHandle,         // hFile\n\t\t0,                  // lpAttributes (NULL)\n\t\tpageReadwrite,      // flProtect\n\t\t0,                  // dwMaximumSizeHigh\n\t\tuintptr(totalSize), // dwMaximumSizeLow\n\t\t0,                  // lpName (NULL for unnamed mapping)\n\t)\n\n\tif mapHandle == 0 {\n\t\treturn nil, fmt.Errorf(\"CreateFileMappingW failed: %v\", err)\n\t}\n\n\t// Map view of file\n\tdata, _, err := mapViewOfFile.Call(\n\t\tmapHandle,          // hFileMappingObject\n\t\tfileMapAllAccess,   // dwDesiredAccess\n\t\t0,                  // dwFileOffsetHigh\n\t\t0,                  // dwFileOffsetLow\n\t\tuintptr(totalSize), // dwNumberOfBytesToMap\n\t)\n\n\tif data == 0 {\n\t\t_, _, _ = closeHandle.Call(mapHandle)\n\t\treturn nil, fmt.Errorf(\"MapViewOfFile failed: %v\", err)\n\t}\n\n\treturn &PersistentSharedString{\n\t\tfilePath:   filePath,\n\t\tfileHandle: fileHandle,\n\t\tmapHandle:  mapHandle,\n\t\tdata:       data,\n\t\tsize:       size,\n\t}, nil\n}\n\n// SetString stores a string in the memory-mapped file (automatically persisted)\nfunc (pss *PersistentSharedString) SetString(value string) error {\n\tstrBytes := []byte(value)\n\n\tif len(strBytes) > pss.size {\n\t\treturn fmt.Errorf(\"string too large for allocated space (%d > %d)\", len(strBytes), pss.size)\n\t}\n\n\tbasePtr := unsafe.Pointer(pss.data)\n\n\t// Write length as first 4 bytes (little-endian)\n\tlengthPtr := (*uint32)(basePtr)\n\t*lengthPtr = uint32(len(strBytes))\n\n\t// Write string data starting at offset 4\n\tif len(strBytes) > 0 {\n\t\tstringPtr := unsafe.Add(basePtr, 4)\n\t\tstringSlice := unsafe.Slice((*byte)(stringPtr), len(strBytes))\n\t\tcopy(stringSlice, strBytes)\n\t}\n\n\t// Write null terminator\n\tnullPtr := (*byte)(unsafe.Add(basePtr, 4+len(strBytes)))\n\t*nullPtr = 0\n\n\t// No need to explicitly flush - Windows handles this automatically\n\treturn nil\n}\n\nfunc (pss *PersistentSharedString) bytes() []byte {\n\tbasePtr := unsafe.Pointer(pss.data)\n\n\t// Read length from first 4 bytes\n\tlengthPtr := (*uint32)(basePtr)\n\tlength := *lengthPtr\n\n\tif length == 0 {\n\t\tlog.Debug(\"empty string\")\n\t\treturn []byte{0}\n\t}\n\n\tif length > uint32(pss.size) {\n\t\tlog.Error(fmt.Errorf(\"corrupted data: length %d exceeds allocated size %d\", length, pss.size))\n\t\treturn []byte{0}\n\t}\n\n\t// Read string data starting at offset 4\n\tstringPtr := unsafe.Add(basePtr, 4)\n\tstringSlice := unsafe.Slice((*byte)(stringPtr), length)\n\n\t// Convert to string\n\tresult := make([]byte, length)\n\tcopy(result, stringSlice)\n\treturn result\n}\n\n// Close closes the memory-mapped file and handles\nfunc (pss *PersistentSharedString) close() error {\n\tvar err error\n\n\tif pss.data != 0 {\n\t\tif ret, _, e := unmapViewOfFile.Call(pss.data); ret == 0 {\n\t\t\terr = fmt.Errorf(\"UnmapViewOfFile failed: %v\", e)\n\t\t}\n\t\tpss.data = 0\n\t}\n\n\tif pss.mapHandle != 0 {\n\t\tif ret, _, e := closeHandle.Call(pss.mapHandle); ret == 0 {\n\t\t\tif err == nil {\n\t\t\t\terr = fmt.Errorf(\"CloseHandle (mapping) failed: %v\", e)\n\t\t\t}\n\t\t}\n\t\tpss.mapHandle = 0\n\t}\n\n\tif pss.fileHandle != 0 {\n\t\tif ret, _, e := closeHandle.Call(pss.fileHandle); ret == 0 {\n\t\t\tif err == nil {\n\t\t\t\terr = fmt.Errorf(\"CloseHandle (file) failed: %v\", e)\n\t\t\t}\n\t\t}\n\t\tpss.fileHandle = 0\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "src/cache/file_unix.go",
    "content": "//go:build !windows\n\npackage cache\n\nimport (\n\t\"io\"\n\t\"os\"\n)\n\nfunc openFile(filePath string) (io.ReadWriteCloser, error) {\n\treturn os.OpenFile(filePath, os.O_CREATE|os.O_RDWR, 0o644)\n}\n"
  },
  {
    "path": "src/cache/file_windows.go",
    "content": "package cache\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\n// persistentStringRWCloser implements io.ReadWriteCloser for PersistentSharedString\ntype persistentStringRWCloser struct {\n\tpss      *PersistentSharedString\n\tbuf      *bytes.Buffer\n\tfilePath string\n\tdirty    bool\n}\n\nfunc NewPersistentStringRWCloser(pss *PersistentSharedString) io.ReadWriteCloser {\n\treturn &persistentStringRWCloser{\n\t\tpss:      pss,\n\t\tbuf:      bytes.NewBuffer(pss.bytes()),\n\t\tfilePath: pss.filePath,\n\t}\n}\n\nfunc (rw *persistentStringRWCloser) Read(p []byte) (int, error) {\n\treturn rw.buf.Read(p)\n}\n\nfunc (rw *persistentStringRWCloser) Write(p []byte) (int, error) {\n\tif !rw.dirty {\n\t\trw.buf.Reset()\n\t\trw.dirty = true\n\t}\n\n\treturn rw.buf.Write(p)\n}\n\nfunc (rw *persistentStringRWCloser) Close() error {\n\tdefer rw.pss.close()\n\n\tif !rw.dirty {\n\t\treturn nil\n\t}\n\n\tdata := rw.buf.String()\n\tdataSize := len(data)\n\n\t// Check if the data fits in the current allocation\n\tif dataSize <= rw.pss.size {\n\t\treturn rw.pss.SetString(data)\n\t}\n\n\t// Data is too large, need to recreate with larger size\n\tlog.Debugf(\"cache data size (%d) exceeds current allocation (%d), recreating file\", dataSize, rw.pss.size)\n\n\t// Calculate new size with some growth factor (1.5x) to reduce future reallocations\n\tnewSize := max(dataSize+(dataSize/2), minStringSize)\n\tif newSize > maxStringSize {\n\t\treturn fmt.Errorf(\"required cache size %d exceeds maximum %d\", dataSize, maxStringSize)\n\t}\n\n\t// Close current mapping before recreating\n\tif err := rw.pss.close(); err != nil {\n\t\tlog.Error(err)\n\t}\n\n\t// Create new file with larger size\n\tnewPss, err := createOrOpenPersistentStringWithSize(rw.filePath, newSize)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to recreate cache file with size %d: %v\", newSize, err)\n\t}\n\n\t// Write the data to the new file\n\treturn newPss.SetString(data)\n}\n\nfunc openFile(filePath string) (io.ReadWriteCloser, error) {\n\tpss, err := createOrOpenPersistentString(filePath)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\treturn NewPersistentStringRWCloser(pss), nil\n}\n"
  },
  {
    "path": "src/cache/init.go",
    "content": "package cache\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Option func()\n\nvar (\n\tsessionID  string\n\tnewSession bool\n\tpersist    bool\n\tnoSession  bool\n\tonce       sync.Once\n)\n\nvar NewSession Option = func() {\n\tlog.Debug(\"starting a new session\")\n\tnewSession = true\n}\n\nvar Persist Option = func() {\n\tlog.Debug(\"enable persistent cache\")\n\tpersist = true\n}\n\nvar NoSession Option = func() {\n\tlog.Debug(\"disable session cache\")\n\tnoSession = true\n}\n\nfunc Init(shell string, options ...Option) {\n\tfor _, opt := range options {\n\t\topt()\n\t}\n\n\tDevice.init(DeviceStore, persist)\n\n\tif noSession {\n\t\treturn\n\t}\n\n\tsessionFileName := fmt.Sprintf(\"%s.%s.%s\", shell, SessionID(), DeviceStore)\n\tSession.init(sessionFileName, persist)\n}\n\nfunc SessionID() string {\n\tdefer log.Trace(time.Now())\n\n\tonce.Do(func() {\n\t\tif newSession {\n\t\t\tsessionID = uuid.NewString()\n\t\t\treturn\n\t\t}\n\n\t\tsessionID = os.Getenv(\"POSH_SESSION_ID\")\n\t\tif sessionID == \"\" {\n\t\t\tsessionID = uuid.NewString()\n\t\t}\n\t})\n\n\treturn sessionID\n}\n\nfunc Close() {\n\tSession.close()\n\tDevice.close()\n}\n"
  },
  {
    "path": "src/cache/path.go",
    "content": "package cache\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\nvar cachePath string\n\nfunc Path() string {\n\tdefer log.Trace(time.Now())\n\n\tif cachePath != \"\" {\n\t\treturn cachePath\n\t}\n\n\tvar OK bool\n\n\t// allow the user to set the cache path using OMP_CACHE_DIR\n\tif cachePath, OK = returnOrBuildCachePath(os.Getenv(\"OMP_CACHE_DIR\")); OK {\n\t\treturn cachePath\n\t}\n\n\tif cachePath, OK = platformCachePath(); OK {\n\t\treturn cachePath\n\t}\n\n\t// try to create the cache folder in the user's home directory if non-existent\n\tdotCache := filepath.Join(path.Home(), \".cache\")\n\tif _, err := os.Stat(dotCache); err != nil {\n\t\t_ = os.Mkdir(dotCache, 0o755)\n\t}\n\n\t// HOME cache folder\n\tif cachePath, OK = returnOrBuildCachePath(dotCache); OK {\n\t\treturn cachePath\n\t}\n\n\treturn cachePath\n}\n\nfunc returnOrBuildCachePath(input string) (string, bool) {\n\t// validate root path\n\tif _, err := os.Stat(input); err != nil {\n\t\treturn \"\", false\n\t}\n\n\t// validate oh-my-posh folder, if non existent, create it\n\tcachePath := filepath.Join(input, \"oh-my-posh\")\n\tif _, err := os.Stat(cachePath); err == nil {\n\t\treturn cachePath, true\n\t}\n\n\tif err := os.Mkdir(cachePath, 0o755); err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn cachePath, true\n}\n"
  },
  {
    "path": "src/cache/path_unix.go",
    "content": "//go:build !windows\n\npackage cache\n\nimport \"os\"\n\nfunc platformCachePath() (string, bool) {\n\tif cachePath, OK := returnOrBuildCachePath(os.Getenv(\"XDG_CACHE_HOME\")); OK {\n\t\treturn cachePath, true\n\t}\n\n\treturn \"\", false\n}\n\nfunc PackageFamilyName() (string, bool) {\n\treturn \"\", false\n}\n"
  },
  {
    "path": "src/cache/path_windows.go",
    "content": "package cache\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc platformCachePath() (string, bool) {\n\tif pfn, OK := PackageFamilyName(); OK {\n\t\t// WINDOWS MSIX cache folder, will only be present when oh-my-posh is installed via MSIX\n\t\tmsixLocalAppData := filepath.Join(os.Getenv(\"LOCALAPPDATA\"), \"Packages\", pfn, \"LocalCache\", \"Local\")\n\t\tif cachePath, OK := returnOrBuildCachePath(msixLocalAppData); OK {\n\t\t\treturn cachePath, true\n\t\t}\n\t}\n\n\t// WINDOWS cache folder, should not exist elsewhere\n\tif cachePath, OK := returnOrBuildCachePath(os.Getenv(\"LOCALAPPDATA\")); OK {\n\t\treturn cachePath, true\n\t}\n\n\treturn \"\", false\n}\n\nfunc PackageFamilyName() (string, bool) {\n\tdefer log.Trace(time.Now())\n\n\tkernel32 := syscall.NewLazyDLL(\"kernel32.dll\")\n\tprocGetCurrentPackageFamilyName := kernel32.NewProc(\"GetCurrentPackageFamilyName\")\n\n\tvar length uint32 = 256\n\tbuf := make([]uint16, length)\n\tret, _, _ := procGetCurrentPackageFamilyName.Call(\n\t\tuintptr(unsafe.Pointer(&length)),\n\t\tuintptr(unsafe.Pointer(&buf[0])),\n\t)\n\n\tif ret != 0 {\n\t\tlog.Debug(\"failed to get PackageFamilyName\")\n\t\treturn \"\", false\n\t}\n\n\tpfn := syscall.UTF16ToString(buf)\n\tlog.Debug(\"PackageFamilyName:\", pfn)\n\n\treturn pfn, true\n}\n"
  },
  {
    "path": "src/cache/store.go",
    "content": "package cache\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n)\n\ntype store struct {\n\tcache    *maps.Concurrent[*Entry[any]]\n\tfilePath string\n\tdirty    bool\n\tpersist  bool\n}\n\nvar (\n\tsession *store\n\tdevice  *store\n)\n\ntype Store string\n\nconst (\n\tSession Store  = \"session\"\n\tDevice  Store  = \"device\"\n\tTTL     string = \"ttl\"\n)\n\nfunc (s Store) new() *store {\n\treturn &store{\n\t\tcache: maps.NewConcurrent[*Entry[any]](),\n\t}\n}\n\n// getStore returns the appropriate store based on the Store identifier\nfunc (s Store) get() *store {\n\tswitch s { //nolint:exhaustive\n\tcase Device:\n\t\tif device == nil {\n\t\t\tdevice = s.new()\n\t\t}\n\n\t\treturn device\n\tdefault:\n\t\tif session == nil {\n\t\t\tsession = s.new()\n\t\t}\n\n\t\treturn session\n\t}\n}\n\n// Init initializes a store with the given file path\nfunc (s Store) init(filePath string, persist bool) {\n\tdefer log.Trace(time.Now(), string(s), filePath)\n\n\tstore := s.get()\n\tstore.cache = maps.NewConcurrent[*Entry[any]]()\n\tstore.filePath = filepath.Join(Path(), filePath)\n\tstore.persist = persist\n\n\treader, err := openFile(store.filePath)\n\tif err != nil {\n\t\t// set to dirty so we create it on close\n\t\tlog.Error(err)\n\t\tstore.dirty = true\n\t\treturn\n\t}\n\n\tdefer reader.Close()\n\n\tvar list maps.Simple[*Entry[any]]\n\n\tdec := gob.NewDecoder(reader)\n\tif err := dec.Decode(&list); err != nil {\n\t\tlog.Error(err)\n\t\t// If gob decoding fails, the cache file might be from the old format\n\t\t// Set dirty to true so we recreate it in gob format\n\t\tstore.dirty = true\n\t\treturn\n\t}\n\n\tfor key, entry := range list {\n\t\tif entry.Expired() {\n\t\t\tlog.Debugf(\"(%s) skipping expired key: %s\", string(s), key)\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Debugf(\"(%s) loading %s\", string(s), key)\n\t\tstore.cache.Set(key, entry)\n\t}\n}\n\n// touchSessionFile updates the session file's modification time if it's older than 1 hour.\n// This prevents stale session cache files from being cleaned up while reducing steady-state overhead.\nfunc touchSessionFile(filePath string) {\n\tinfo, err := os.Stat(filePath)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tif time.Since(info.ModTime()) <= time.Hour {\n\t\treturn\n\t}\n\n\tif err := os.Chtimes(filePath, time.Now(), time.Now()); err != nil {\n\t\tlog.Error(err)\n\t}\n}\n\nfunc (s Store) close() {\n\tdefer log.Trace(time.Now(), string(s))\n\n\tstore := s.get()\n\tif store == nil || !store.persist || !store.dirty {\n\t\tif s == Session && store != nil && store.filePath != \"\" {\n\t\t\ttouchSessionFile(store.filePath)\n\t\t}\n\n\t\tlog.Debugf(\"(%s) not persisting\", string(s))\n\t\treturn\n\t}\n\n\tcache := store.cache.ToSimple()\n\n\tfile, err := openFile(store.filePath)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\tif err := file.Close(); err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t}()\n\n\tenc := gob.NewEncoder(file)\n\tif err := enc.Encode(cache); err != nil {\n\t\tlog.Error(err)\n\t}\n}\n\n// Get retrieves a typed value from the specified store\nfunc Get[T any](s Store, key string) (T, bool) {\n\tvar zero T\n\tdefer log.Trace(time.Now(), string(s), key)\n\n\tstore := s.get()\n\tif store == nil {\n\t\tlog.Debugf(\"(%s) store is nil\", string(s))\n\t\treturn zero, false\n\t}\n\n\tentry, found := store.cache.Get(key)\n\tif !found {\n\t\tlog.Debugf(\"(%s) key not found: %s\", string(s), key)\n\t\treturn zero, false\n\t}\n\n\tif entry.Expired() {\n\t\tlog.Debugf(\"(%s) key expired: %s\", string(s), key)\n\t\tstore.cache.Delete(key)\n\t\tstore.dirty = true\n\t\treturn zero, false\n\t}\n\n\t// Type assertion to get the typed value\n\tif typed, ok := entry.Value.(T); ok {\n\t\tlog.Debugf(\"(%s) found entry: %s - %v\", string(s), key, typed)\n\t\treturn typed, true\n\t}\n\n\tlog.Error(fmt.Errorf(\"(%s) type mismatch for key: %s. Got %T, expected %T\", string(s), key, entry.Value, zero))\n\treturn zero, false\n}\n\n// Set stores a typed value in the specified store\nfunc Set[T any](s Store, key string, value T, duration Duration) {\n\tdefer log.Trace(time.Now(), string(s), key)\n\n\tstore := s.get()\n\tif store == nil {\n\t\tlog.Debugf(\"(%s) store is nil\", string(s))\n\t\treturn\n\t}\n\n\tseconds := duration.Seconds()\n\tif seconds == 0 {\n\t\treturn\n\t}\n\n\tlog.Debugf(\"(%s) setting entry: %s - %v with duration: %s\", string(s), key, value, string(duration))\n\n\tstore.cache.Set(key, &Entry[any]{\n\t\tValue:     value,\n\t\tTimestamp: time.Now().Unix(),\n\t\tTTL:       seconds,\n\t})\n\n\tstore.dirty = true\n}\n\n// Delete removes a key from the specified store\nfunc Delete(s Store, key string) {\n\tdefer log.Trace(time.Now(), string(s), key)\n\n\tstore := s.get()\n\tif store == nil {\n\t\tlog.Debugf(\"(%s) store is nil\", string(s))\n\t\treturn\n\t}\n\n\tlog.Debugf(\"(%s) deleting key: %s\", string(s), key)\n\tstore.cache.Delete(key)\n\tstore.dirty = true\n}\n\nfunc DeleteAll(s Store) {\n\tdefer log.Trace(time.Now(), string(s))\n\n\tstore := s.get()\n\tif store == nil {\n\t\tlog.Debugf(\"(%s) store is nil\", string(s))\n\t\treturn\n\t}\n\n\tstore.cache = maps.NewConcurrent[*Entry[any]]()\n\tstore.dirty = true\n}\n\nfunc Print(s Store) string {\n\tdefer log.Trace(time.Now(), string(s))\n\n\tstore := s.get()\n\tif store == nil {\n\t\treturn fmt.Sprintf(\"Store %s is nil\", string(s))\n\t}\n\n\tcache := store.cache.ToSimple()\n\tif len(cache) == 0 {\n\t\treturn fmt.Sprintf(\"Store %s is empty\", string(s))\n\t}\n\n\tvar builder strings.Builder\n\n\tfor key, entry := range cache {\n\t\tbuilder.WriteString(\"\\n\")\n\n\t\tif entry.Expired() {\n\t\t\tfmt.Fprintf(&builder, \"Key: %s [EXPIRED]\\n\", key)\n\t\t\tbuilder.WriteString(\"\\n\")\n\t\t\tcontinue\n\t\t}\n\n\t\tvar ttlInfo string\n\t\tif entry.TTL < 0 {\n\t\t\tttlInfo = \"never expires\"\n\t\t}\n\t\tif entry.TTL >= 0 {\n\t\t\texpiresAt := time.Unix(entry.Timestamp+int64(entry.TTL), 0)\n\t\t\tttlInfo = fmt.Sprintf(\"expires at %s\", expiresAt.Format(\"2006-01-02 15:04:05\"))\n\t\t}\n\n\t\tfmt.Fprintf(&builder, \"Key: %s\\n\", key)\n\t\tfmt.Fprintf(&builder, \"  Value: %s\\n\", fmt.Sprintf(\"%#v\", entry.Value))\n\t\tfmt.Fprintf(&builder, \"  Type: %T\\n\", entry.Value)\n\t\tfmt.Fprintf(&builder, \"  Created: %s\\n\", time.Unix(entry.Timestamp, 0).Format(\"2006-01-02 15:04:05\"))\n\t\tfmt.Fprintf(&builder, \"  TTL: %s\\n\", ttlInfo)\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "src/cache/store_test.go",
    "content": "package cache\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStore(t *testing.T) {\n\tcases := []struct {\n\t\tsetupFunc func() *store\n\t\ttestFunc  func(t *testing.T)\n\t\tname      string\n\t}{\n\t\t{\n\t\t\tname: \"Print store with data\",\n\t\t\tsetupFunc: func() *store {\n\t\t\t\ttestStore := Session.new()\n\t\t\t\ttestStore.cache.Set(\"test_key1\", &Entry[any]{\n\t\t\t\t\tValue:     \"test_value1\",\n\t\t\t\t\tTimestamp: time.Now().Unix(),\n\t\t\t\t\tTTL:       3600, // 1 hour\n\t\t\t\t})\n\t\t\t\ttestStore.cache.Set(\"test_key2\", &Entry[any]{\n\t\t\t\t\tValue:     42,\n\t\t\t\t\tTimestamp: time.Now().Unix(),\n\t\t\t\t\tTTL:       -1, // never expires\n\t\t\t\t})\n\t\t\t\ttestStore.cache.Set(\"expired_key\", &Entry[any]{\n\t\t\t\t\tValue:     \"expired_value\",\n\t\t\t\t\tTimestamp: time.Now().Unix() - 7200, // 2 hours ago\n\t\t\t\t\tTTL:       3600,                     // 1 hour (should be expired)\n\t\t\t\t})\n\t\t\t\tsession = testStore\n\t\t\t\treturn testStore\n\t\t\t},\n\t\t\ttestFunc: func(t *testing.T) {\n\t\t\t\tresult := Print(Session)\n\t\t\t\tassert.Contains(t, result, \"Key: test_key1\")\n\t\t\t\tassert.Contains(t, result, `Value: \"test_value1\"`) // Note: quotes are included in output\n\t\t\t\tassert.Contains(t, result, \"Type: string\")\n\t\t\t\tassert.Contains(t, result, \"Key: test_key2\")\n\t\t\t\tassert.Contains(t, result, \"Value: 42\")\n\t\t\t\tassert.Contains(t, result, \"Type: int\")\n\t\t\t\tassert.Contains(t, result, \"Key: expired_key [EXPIRED]\")\n\t\t\t\tassert.Contains(t, result, \"never expires\")\n\t\t\t\tassert.Contains(t, result, \"expires at\")\n\n\t\t\t\t// Verify structure\n\t\t\t\tlines := strings.Split(result, \"\\n\")\n\t\t\t\tassert.True(t, len(lines) > 10, \"Output should have multiple lines\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Print empty store\",\n\t\t\tsetupFunc: func() *store {\n\t\t\t\ttestStore := Session.new()\n\t\t\t\tsession = testStore\n\t\t\t\treturn testStore\n\t\t\t},\n\t\t\ttestFunc: func(t *testing.T) {\n\t\t\t\tresult := Print(Session)\n\t\t\t\tassert.Contains(t, result, \"Store session is empty\")\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: \"Print nil store check\",\n\t\t\tsetupFunc: func() *store {\n\t\t\t\ttestStore := Session.new()\n\t\t\t\tsession = testStore\n\t\t\t\treturn testStore\n\t\t\t},\n\t\t\ttestFunc: func(t *testing.T) {\n\t\t\t\t// Since get() always creates a store, we test empty store behavior\n\t\t\t\tresult := Print(Session)\n\t\t\t\tassert.Contains(t, result, \"Store session is empty\")\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\ttc.setupFunc()\n\t\t\ttc.testFunc(t)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/cache/template.go",
    "content": "package cache\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n)\n\ntype Template struct {\n\tSegments *maps.Concurrent[any]\n\tSimpleTemplate\n}\n\ntype SimpleTemplate struct {\n\tSegmentsCache maps.Simple[any]\n\tVar           maps.Simple[any]\n\tPWD           string\n\tFolder        string\n\tPSWD          string\n\tUserName      string\n\tHostName      string\n\tShellVersion  string\n\tShell         string\n\tAbsolutePWD   string\n\tOS            string\n\tVersion       string\n\tPromptCount   int\n\tSHLVL         int\n\tJobs          int\n\tCode          int\n\tWSL           bool\n\tRoot          bool\n}\n\nfunc (t *Template) AddSegmentData(key string, value any) {\n\tt.Segments.Set(key, value)\n}\n\nfunc (t *Template) RemoveSegmentData(key string) {\n\tt.Segments.Delete(key)\n}\n"
  },
  {
    "path": "src/cli/args.go",
    "content": "package cli\n\nimport (\n\t\"github.com/spf13/cobra\"\n)\n\nfunc NoArgsOrOneValidArg(cmd *cobra.Command, args []string) error {\n\tif len(args) == 0 {\n\t\treturn nil\n\t}\n\n\tif err := cobra.ExactArgs(1)(cmd, args); err != nil {\n\t\treturn err\n\t}\n\n\treturn cobra.OnlyValidArgs(cmd, args)\n}\n"
  },
  {
    "path": "src/cli/auth/cli.go",
    "content": "package auth\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/charmbracelet/bubbles/spinner\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/charmbracelet/lipgloss\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nvar (\n\tprogram   *tea.Program\n\ttextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 2)\n)\n\ntype stateMsg state\n\ntype state int\n\nconst (\n\tcode state = iota\n\ttoken\n\tdone\n)\n\n// ErrorGetter is implemented by auth models to get the error.\ntype ErrorGetter interface {\n\tGetError() error\n}\n\nfunc setState(message state) {\n\tif program == nil {\n\t\treturn\n\t}\n\n\tprogram.Send(stateMsg(message))\n}\n\ntype model struct {\n\tenv     runtime.Environment\n\terr     error\n\tspinner *spinner.Model\n\tstatus  func(error) string\n\tcode    string\n\tstate   state\n}\n\nfunc (m *model) Init() tea.Cmd {\n\ts := spinner.New()\n\ts.Spinner = spinner.Globe\n\ts.Style = lipgloss.NewStyle().Foreground(lipgloss.Color(\"170\"))\n\tm.spinner = &s\n\n\treturn m.spinner.Tick\n}\n\nfunc (m *model) GetError() error {\n\treturn m.err\n}\n\nfunc (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tswitch msg := msg.(type) {\n\tcase stateMsg:\n\t\tm.state = state(msg)\n\t\tif m.state == done {\n\t\t\treturn m, tea.Quit\n\t\t}\n\n\t\treturn m, nil\n\n\tdefault:\n\t\ts, cmd := m.spinner.Update(msg)\n\t\tm.spinner = &s\n\t\treturn m, cmd\n\t}\n}\n\nfunc (m *model) View() string {\n\tvar message string\n\n\tswitch m.state {\n\tcase code:\n\t\tmessage = fmt.Sprintf(\"%s Fetching code for authentication\", m.spinner.View())\n\tcase token:\n\t\tmessage = fmt.Sprintf(\"%s Fetching token with code: %s\", m.spinner.View(), m.code)\n\tcase done:\n\t\tmessage = m.status(m.err)\n\t}\n\n\treturn textStyle.Render(message)\n}\n\nfunc Run(m tea.Model) error {\n\tprogram = tea.NewProgram(m)\n\tresultModel, _ := program.Run()\n\n\tif eg, ok := resultModel.(ErrorGetter); ok {\n\t\treturn eg.GetError()\n\t}\n\n\tlog.Debug(\"model does not implement ErrorGetter\")\n\treturn nil\n}\n"
  },
  {
    "path": "src/cli/auth/copilot.go",
    "content": "package auth\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\thttplib \"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nconst (\n\t// GitHub Copilot's OAuth client ID - This is a public client ID used for device code flow\n\tCopilotClientID = \"Iv1.b507a08c87ecfe98\"\n\tCopilotScope    = \"read:email\"\n\n\tCopilotDeviceCodeURL  = \"https://github.com/login/device/code\"\n\tCopilotAccessTokenURL = \"https://github.com/login/oauth/access_token\"\n\n\tCopilotTokenKey = \"copilot_token\"\n)\n\n// DeviceCodeResponse represents the response from GitHub's device code endpoint.\ntype DeviceCodeResponse struct {\n\tDeviceCode      string `json:\"device_code\"`\n\tUserCode        string `json:\"user_code\"`\n\tVerificationURI string `json:\"verification_uri\"`\n\tExpiresIn       int    `json:\"expires_in\"`\n\tInterval        int    `json:\"interval\"`\n}\n\n// AccessTokenResponse represents the response from GitHub's access token endpoint.\ntype AccessTokenResponse struct {\n\tAccessToken      string `json:\"access_token\"`\n\tTokenType        string `json:\"token_type\"`\n\tScope            string `json:\"scope\"`\n\tError            string `json:\"error\"`\n\tErrorDescription string `json:\"error_description\"`\n}\n\nfunc NewCopilot(env runtime.Environment) *CopilotAuth {\n\treturn &CopilotAuth{\n\t\tmodel: model{\n\t\t\tenv: env,\n\t\t},\n\t}\n}\n\ntype CopilotAuth struct {\n\tdeviceCodeExpiry time.Time\n\tverificationURI  string\n\tmodel\n\tlastState state\n}\n\nfunc (c *CopilotAuth) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tswitch msg := msg.(type) {\n\tcase stateMsg:\n\t\tc.state = state(msg)\n\t\tif c.state == done {\n\t\t\treturn c, tea.Quit\n\t\t}\n\n\t\treturn c, nil\n\n\tdefault:\n\t\ts, cmd := c.spinner.Update(msg)\n\t\tc.spinner = &s\n\t\treturn c, cmd\n\t}\n}\n\nfunc (c *CopilotAuth) Init() tea.Cmd {\n\tc.model.status = c.status\n\tcmd := c.model.Init()\n\tgo c.Authenticate()\n\treturn cmd\n}\n\nfunc (c *CopilotAuth) Authenticate() {\n\tsetState(code)\n\tc.lastState = code\n\n\tdeviceCode, err := c.requestDeviceCode()\n\tif err != nil {\n\t\tc.err = err\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\tc.code = deviceCode.UserCode\n\tc.verificationURI = deviceCode.VerificationURI\n\tc.deviceCodeExpiry = time.Now().Add(time.Duration(deviceCode.ExpiresIn) * time.Second)\n\n\tsetState(token)\n\tc.lastState = token\n\n\tinterval := max(deviceCode.Interval, 5)\n\n\ttoken, err := c.pollForToken(deviceCode.DeviceCode, interval)\n\tif err != nil {\n\t\tc.err = err\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\tif token == \"\" {\n\t\tc.err = fmt.Errorf(\"received empty token\")\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\tcache.Set(cache.Device, CopilotTokenKey, token, cache.TWOYEARS)\n\n\tsetState(done)\n}\n\nfunc (c *CopilotAuth) requestDeviceCode() (*DeviceCodeResponse, error) {\n\tbody := fmt.Sprintf(\"client_id=%s&scope=%s\", CopilotClientID, CopilotScope)\n\n\tmodifyRequest := func(request *httplib.Request) {\n\t\trequest.Method = httplib.MethodPost\n\t\trequest.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\trequest.Header.Set(\"Accept\", \"application/json\")\n\t}\n\n\tresponse, err := c.env.HTTPRequest(CopilotDeviceCodeURL, strings.NewReader(body), 30000, modifyRequest)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to request device code: %w\", err)\n\t}\n\n\tvar result DeviceCodeResponse\n\tif err := json.Unmarshal(response, &result); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse device code response: %w\", err)\n\t}\n\n\treturn &result, nil\n}\n\nfunc (c *CopilotAuth) pollForToken(deviceCode string, interval int) (string, error) {\n\tmodifyRequest := func(request *httplib.Request) {\n\t\trequest.Method = httplib.MethodPost\n\t\trequest.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t\trequest.Header.Set(\"Accept\", \"application/json\")\n\t}\n\n\tfor {\n\t\tif time.Now().After(c.deviceCodeExpiry) {\n\t\t\treturn \"\", fmt.Errorf(\"device code expired, please try again\")\n\t\t}\n\n\t\ttime.Sleep(time.Duration(interval) * time.Second)\n\n\t\tbody := fmt.Sprintf(\"client_id=%s&device_code=%s&grant_type=urn:ietf:params:oauth:grant-type:device_code\", CopilotClientID, deviceCode)\n\t\tresponse, err := c.env.HTTPRequest(CopilotAccessTokenURL, strings.NewReader(body), 30000, modifyRequest)\n\t\tif err != nil {\n\t\t\t// Log error but continue polling\n\t\t\tcontinue\n\t\t}\n\n\t\tvar result AccessTokenResponse\n\t\tif err := json.Unmarshal(response, &result); err != nil {\n\t\t\t// Log error but continue polling\n\t\t\tcontinue\n\t\t}\n\n\t\tif result.AccessToken != \"\" {\n\t\t\treturn result.AccessToken, nil\n\t\t}\n\n\t\tswitch result.Error {\n\t\tcase \"authorization_pending\":\n\t\t\tcontinue\n\t\tcase \"slow_down\":\n\t\t\tinterval += 5\n\t\t\tcontinue\n\t\tcase \"expired_token\":\n\t\t\treturn \"\", fmt.Errorf(\"device code expired, please try again\")\n\t\tcase \"access_denied\":\n\t\t\treturn \"\", fmt.Errorf(\"access was denied by the user\")\n\t\tdefault:\n\t\t\tif result.Error != \"\" {\n\t\t\t\treturn \"\", fmt.Errorf(\"authentication error: %s - %s\", result.Error, result.ErrorDescription)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (c *CopilotAuth) status(err error) string {\n\tif err == nil {\n\t\treturn \"Successfully authenticated with GitHub Copilot\"\n\t}\n\n\thttpErr, ok := err.(*http.Error)\n\tif !ok {\n\t\treturn err.Error()\n\t}\n\n\treturn fmt.Sprintf(\"HTTP error %d: %s\", httpErr.StatusCode, httpErr.Error())\n}\n\nfunc (c *CopilotAuth) View() string {\n\tvar message string\n\n\tswitch c.state {\n\tcase code:\n\t\tmessage = fmt.Sprintf(\"%s Requesting device code from GitHub\", c.spinner.View())\n\tcase token:\n\t\tmessage = fmt.Sprintf(\"%s Please visit %s and enter code: %s\", c.spinner.View(), c.verificationURI, c.code)\n\tcase done:\n\t\tmessage = c.status(c.err)\n\t}\n\n\treturn textStyle.Render(message)\n}\n"
  },
  {
    "path": "src/cli/auth/ytmda.go",
    "content": "package auth\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\thttplib \"net/http\"\n\t\"strings\"\n\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nconst (\n\tYTMDABASEURL = \"http://localhost:9863/api/v1\"\n\tYTMDATOKEN   = \"ytmda_token\"\n\n\ttokenURL = YTMDABASEURL + \"/auth/request\"\n\tcodeURL  = YTMDABASEURL + \"/auth/requestcode\"\n)\n\nfunc NewYtmda(env runtime.Environment) *Ytmda {\n\treturn &Ytmda{\n\t\tmodel: model{\n\t\t\tenv: env,\n\t\t},\n\t}\n}\n\ntype Ytmda struct {\n\tmodel\n\tlastState state\n}\n\nfunc (y *Ytmda) Init() tea.Cmd {\n\ty.model.status = y.status\n\tcmd := y.model.Init()\n\tgo y.Authenticate()\n\treturn cmd\n}\n\nfunc (y *Ytmda) Authenticate() {\n\tsetState(code)\n\ty.lastState = code\n\n\tcode, err := y.requestCode()\n\tif err != nil {\n\t\ty.err = err\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\ty.code = code\n\tsetState(token)\n\ty.lastState = token\n\n\ttoken, err := y.requestToken(code)\n\tif err != nil {\n\t\ty.err = err\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\tif token == \"\" {\n\t\ty.err = fmt.Errorf(\"received empty token\")\n\t\tsetState(done)\n\t\treturn\n\t}\n\n\tcache.Set(cache.Session, YTMDATOKEN, token, cache.INFINITE)\n\n\tsetState(done)\n}\n\nfunc (y *Ytmda) requestCode() (string, error) {\n\tbody := fmt.Sprintf(`{\"appId\": \"ohmyposh\", \"appName\": \"oh-my-posh\", \"appVersion\": \"%s\"}`, strings.TrimPrefix(build.Version, \"v\"))\n\n\ttype codeResponse struct {\n\t\tCode string `json:\"code\"`\n\t}\n\n\tresult, err := ytmdaRequest[codeResponse](httplib.MethodPost, codeURL, body, y.env)\n\n\treturn result.Code, err\n}\n\nfunc (y *Ytmda) requestToken(code string) (string, error) {\n\tbody := fmt.Sprintf(`{\"appId\": \"ohmyposh\", \"code\": \"%s\"}`, code)\n\n\ttype tokenResponse struct {\n\t\tToken string `json:\"token\"`\n\t}\n\n\tresult, err := ytmdaRequest[tokenResponse](httplib.MethodPost, tokenURL, body, y.env)\n\n\treturn result.Token, err\n}\n\nfunc ytmdaRequest[a any](method, url, body string, env runtime.Environment, requestModifiers ...http.RequestModifier) (a, error) {\n\tif requestModifiers == nil {\n\t\trequestModifiers = []http.RequestModifier{}\n\t}\n\n\tmodifyRequest := func(request *httplib.Request) {\n\t\trequest.Method = method\n\t\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\trequestModifiers = append(requestModifiers, modifyRequest)\n\n\tvar result a\n\n\tresponse, err := env.HTTPRequest(url, strings.NewReader(body), 50000, requestModifiers...)\n\tif err != nil {\n\t\treturn result, err\n\t}\n\n\terr = json.Unmarshal(response, &result)\n\treturn result, err\n}\n\nfunc (y *Ytmda) status(err error) string {\n\t// get the status code from the error if available\n\tif err == nil {\n\t\treturn \"Successfully authenticated with YouTube Music Desktop App\"\n\t}\n\n\tvar netErr net.Error\n\tif errors.As(err, &netErr) && netErr.Timeout() {\n\t\treturn \"There was a timeout while trying to connect to the YouTube Music Desktop App Companion API. Please try again\"\n\t}\n\n\thttpErr, ok := err.(*http.Error)\n\tif !ok {\n\t\t// if the error is not an http.Error, the service isn't running\n\t\treturn \"YouTube Music Desktop App is not running, please start the Companion API\"\n\t}\n\n\tif httpErr.StatusCode != httplib.StatusForbidden {\n\t\treturn err.Error()\n\t}\n\n\tif y.lastState == token {\n\t\treturn \"Failed to request token with code. Please press Allow in the pop-up window\"\n\t}\n\n\treturn \"Please enable companion authorization in the YouTube Music Desktop App settings\"\n}\n"
  },
  {
    "path": "src/cli/auth/ytmda_test.go",
    "content": "package auth\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\truntime_ \"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestYtdma_Authenticate(t *testing.T) {\n\ttestCases := []struct {\n\t\tname                 string\n\t\trequestCodeResponse  string\n\t\trequestCodeError     error\n\t\trequestTokenResponse string\n\t\trequestTokenError    error\n\t\texpectedError        error\n\t\texpectedToken        string\n\t\tshouldSetToken       bool\n\t}{\n\t\t{\n\t\t\tname:                 \"successful authentication\",\n\t\t\trequestCodeResponse:  `{\"code\":\"test-code-123\"}`,\n\t\t\trequestCodeError:     nil,\n\t\t\trequestTokenResponse: `{\"token\":\"test-token-456\"}`,\n\t\t\trequestTokenError:    nil,\n\t\t\texpectedError:        nil,\n\t\t\texpectedToken:        \"test-token-456\",\n\t\t\tshouldSetToken:       true,\n\t\t},\n\t\t{\n\t\t\tname:                 \"request code fails\",\n\t\t\trequestCodeResponse:  \"\",\n\t\t\trequestCodeError:     errors.New(\"failed to request code\"),\n\t\t\trequestTokenResponse: \"\",\n\t\t\trequestTokenError:    nil,\n\t\t\texpectedError:        errors.New(\"failed to request code\"),\n\t\t\texpectedToken:        \"\",\n\t\t\tshouldSetToken:       false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"request token fails\",\n\t\t\trequestCodeResponse:  `{\"code\":\"test-code-123\"}`,\n\t\t\trequestCodeError:     nil,\n\t\t\trequestTokenResponse: \"\",\n\t\t\trequestTokenError:    errors.New(\"failed to request token\"),\n\t\t\texpectedError:        errors.New(\"failed to request token\"),\n\t\t\texpectedToken:        \"\",\n\t\t\tshouldSetToken:       false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"invalid code response JSON\",\n\t\t\trequestCodeResponse:  `{\"invalid\":\"json\"}`,\n\t\t\trequestCodeError:     nil,\n\t\t\trequestTokenResponse: \"\",\n\t\t\trequestTokenError:    nil,\n\t\t\texpectedError:        errors.New(\"unexpected end of JSON input\"),\n\t\t\texpectedToken:        \"\",\n\t\t\tshouldSetToken:       false,\n\t\t},\n\t\t{\n\t\t\tname:                 \"invalid token response JSON\",\n\t\t\trequestCodeResponse:  `{\"code\":\"test-code-123\"}`,\n\t\t\trequestCodeError:     nil,\n\t\t\trequestTokenResponse: `{\"invalid\":\"json\"}`,\n\t\t\trequestTokenError:    nil,\n\t\t\texpectedError:        errors.New(\"received empty token\"),\n\t\t\texpectedToken:        \"\",\n\t\t\tshouldSetToken:       false,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tenv := &runtime_.Environment{}\n\n\t\t\tenv.On(\"HTTPRequest\", codeURL).Return([]byte(tc.requestCodeResponse), tc.requestCodeError)\n\t\t\tenv.On(\"HTTPRequest\", tokenURL).Return([]byte(tc.requestTokenResponse), tc.requestTokenError)\n\n\t\t\tif tc.shouldSetToken {\n\t\t\t\tcache.Set(cache.Device, YTMDATOKEN, tc.expectedToken, cache.INFINITE)\n\t\t\t}\n\n\t\t\tytmda := &Ytmda{\n\t\t\t\tmodel: model{\n\t\t\t\t\tenv: env,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\tytmda.Authenticate()\n\n\t\t\tif tc.expectedError != nil {\n\t\t\t\trequire.NotNil(t, ytmda.err)\n\t\t\t\tassert.Equal(t, tc.expectedError.Error(), ytmda.err.Error())\n\t\t\t} else {\n\t\t\t\tassert.Nil(t, ytmda.err)\n\t\t\t}\n\n\t\t\tcache.DeleteAll(cache.Device)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/cli/auth.go",
    "content": "package cli\n\nimport (\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/auth\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar authCmd = &cobra.Command{\n\tUse:   \"auth [service]\",\n\tShort: \"Authenticate against a service\",\n\tLong: `Authenticate against a service.\n\nAvailable services:\n\n- copilot: GitHub Copilot API\n- ytmda: YouTube Music Desktop App (YTMDA) API`,\n\tValidArgs: []string{\n\t\t\"copilot\",\n\t\t\"ytmda\",\n\t},\n\tArgs: NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tflags := &runtime.Flags{\n\t\t\tShell: os.Getenv(\"POSH_SHELL\"),\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(flags)\n\n\t\tcache.Init(env.Shell(), cache.Persist)\n\n\t\tdefer func() {\n\t\t\tcache.Close()\n\t\t}()\n\n\t\tswitch args[0] {\n\t\tcase \"copilot\":\n\t\t\tauthenticator := auth.NewCopilot(env)\n\t\t\tif err := auth.Run(authenticator); err != nil {\n\t\t\t\tlog.Error(err)\n\t\t\t\texitcode = 70\n\t\t\t}\n\t\tcase \"ytmda\":\n\t\t\tauthenticator := auth.NewYtmda(env)\n\t\t\tif err := auth.Run(authenticator); err != nil {\n\t\t\t\tlog.Error(err)\n\t\t\t\texitcode = 70\n\t\t\t}\n\t\tdefault:\n\t\t\t_ = cmd.Help()\n\t\t}\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(authCmd)\n}\n"
  },
  {
    "path": "src/cli/cache.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tsession bool\n)\n\n// cacheCmd represents the cache command\nvar cacheCmd = &cobra.Command{\n\tUse:   \"cache [path|clear|ttl|show]\",\n\tShort: \"Interact with the oh-my-posh cache\",\n\tLong: `Interact with the oh-my-posh cache.\n\nYou can do the following:\n\n- path: list cache path\n- clear: remove all cache values\n- ttl: get cache TTL in days\n- show: print a detailed list of all cached values`,\n\tValidArgs: []string{\n\t\t\"path\",\n\t\t\"clear\",\n\t\tcache.TTL,\n\t\t\"show\",\n\t},\n\tArgs: cobra.RangeArgs(1, 2),\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tswitch args[0] {\n\t\tcase \"path\":\n\t\t\tfmt.Println(cache.Path())\n\t\tcase \"clear\":\n\t\t\terr := cache.Clear(true)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(err)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfmt.Println(\"cache cleared\")\n\t\tcase cache.TTL:\n\t\t\t// get the second argument as int\n\t\t\tif len(args) < 2 {\n\t\t\t\tfmt.Println(\"please provide a TTL value in days\")\n\t\t\t\texitcode = 2\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tttl, err := strconv.Atoi(args[1])\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"error parsing TTL:\", err.Error())\n\t\t\t\texitcode = 2\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tcache.Init(os.Getenv(\"POSH_SHELL\"), cache.Persist)\n\t\t\tcache.Set(cache.Device, cache.TTL, ttl, cache.INFINITE)\n\t\t\tcache.Close()\n\t\tcase \"show\":\n\t\t\tcache.Init(os.Getenv(\"POSH_SHELL\"))\n\t\t\tstore := cache.Device\n\t\t\tif session {\n\t\t\t\tstore = cache.Session\n\t\t\t}\n\n\t\t\tfmt.Println(cache.Print(store))\n\t\t}\n\t},\n}\n\nfunc init() {\n\tcacheCmd.Flags().BoolVarP(&session, \"session\", \"s\", false, \"show the session cache\")\n\tRootCmd.AddCommand(cacheCmd)\n}\n"
  },
  {
    "path": "src/cli/claude.go",
    "content": "package cli\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// claudeCmd represents the claude command\nvar claudeCmd = &cobra.Command{\n\tUse:   \"claude\",\n\tShort: \"Render a prompt for Claude Code statusline\",\n\tLong: `Render a prompt for Claude Code statusline integration.\n\nThis command reads Claude Code's contextual JSON data from stdin and renders\na prompt that can include a Claude segment with session information like\nmodel name, costs, tokens, and more.\n\nExample usage in Claude Code settings:\n  \"statusLine\": {\n    \"command\": \"oh-my-posh claude --config ~/.config/ohmyposh/claude.toml\"\n  }`,\n\tArgs: cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tlog.Debug(\"claude command started\")\n\n\t\t// Read JSON from stdin\n\t\tstdinData, err := io.ReadAll(os.Stdin)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debugf(\"received data from stdin: %s\", string(stdinData))\n\n\t\t// Process Claude data and initialize cache\n\t\tprocessClaudeData(stdinData)\n\n\t\tflags := &runtime.Flags{\n\t\t\tConfigPath: configFlag,\n\t\t\tShell:      shell.CLAUDE,\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(flags)\n\n\t\tvar cfg *config.Config\n\n\t\tcfg, err = config.Parse(configFlag)\n\t\tif err != nil {\n\t\t\tcfg = config.Claude()\n\t\t}\n\n\t\ttemplate.Init(env, cfg.Var, cfg.Maps)\n\t\tterminal.Init(shell.CLAUDE)\n\t\tterminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()\n\t\tterminal.Colors = cfg.MakeColors(env)\n\n\t\teng := &prompt.Engine{\n\t\t\tConfig: cfg,\n\t\t\tEnv:    env,\n\t\t}\n\n\t\tdefer func() {\n\t\t\ttemplate.SaveCache()\n\t\t\tcache.Close()\n\t\t}()\n\n\t\tresult := eng.Status()\n\t\tfmt.Print(result)\n\t},\n}\n\n// processClaudeData handles parsing and caching of Claude JSON data\nfunc processClaudeData(stdinData []byte) {\n\tif len(stdinData) == 0 {\n\t\tcache.Init(shell.CLAUDE, cache.Persist, cache.NoSession)\n\t\treturn\n\t}\n\n\tvar claudeData segments.ClaudeData\n\tif err := json.Unmarshal(stdinData, &claudeData); err != nil {\n\t\tlog.Error(err)\n\t\tcache.Init(shell.CLAUDE, cache.Persist, cache.NoSession)\n\t\treturn\n\t}\n\n\tlog.Debugf(\"parsed Claude data: session_id=%s, model=%s\", claudeData.SessionID, claudeData.Model.DisplayName)\n\n\t// Set the session ID from Claude data if available\n\tif claudeData.SessionID != \"\" {\n\t\tos.Setenv(\"POSH_SESSION_ID\", claudeData.SessionID)\n\t\tlog.Debugf(\"set POSH_SESSION_ID to: %s\", claudeData.SessionID)\n\t}\n\n\t// Initialize cache first so we can store the data\n\tcache.Init(shell.CLAUDE, cache.Persist)\n\n\t// Store the parsed data in session cache\n\tcache.Set(cache.Session, cache.CLAUDECACHE, claudeData, cache.INFINITE)\n\tlog.Debug(\"stored Claude data in session cache\")\n}\n\nfunc init() {\n\tRootCmd.AddCommand(claudeCmd)\n}\n"
  },
  {
    "path": "src/cli/config.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/spf13/cobra\"\n)\n\n// configCmd represents the config command\nvar configCmd = &cobra.Command{\n\tUse:   \"config edit\",\n\tShort: \"Interact with the config\",\n\tLong: `Interact with the config.\n\nYou can export, migrate or edit the config (via the editor specified in the environment variable \"EDITOR\").`,\n\tValidArgs: []string{\n\t\t\"edit\",\n\t},\n\tArgs: NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tswitch args[0] {\n\t\tcase \"edit\":\n\t\t\tcache.Init(os.Getenv(\"POSH_SHELL\"))\n\t\t\tif configPath, OK := cache.Get[string](cache.Session, config.SourceKey); OK {\n\t\t\t\texitcode = editFileWithEditor(configPath)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfmt.Println(\"no config found in session cache\")\n\t\t\texitcode = 666\n\t\tdefault:\n\t\t\t_ = cmd.Help()\n\t\t}\n\t},\n}\n\nfunc init() {\n\tconfigCmd.AddCommand(dsc.Command(config.DSC()))\n\tRootCmd.AddCommand(configCmd)\n}\n"
  },
  {
    "path": "src/cli/config_export.go",
    "content": "package cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tformat string\n\toutput string\n)\n\n// exportCmd represents the export command\nvar exportCmd = &cobra.Command{\n\tUse:   \"export\",\n\tShort: \"Export your config\",\n\tLong: `Export your config.\n\nYou can choose to print the output to stdout, or export your config in the format of your choice.\n\nExample usage:\n\n> oh-my-posh config export --config ~/myconfig.omp.json --format toml\n\nExports the config file \"~/myconfig.omp.json\" in TOML format and prints the result to stdout.\n\n> oh-my-posh config export --output ~/new_config.omp.json\n\nExports the current config to \"~/new_config.omp.json\" (in JSON format).`,\n\tArgs: cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tif output == \"\" && format == \"\" {\n\t\t\t// usage error\n\t\t\tfmt.Println(\"neither output path nor export format is specified\")\n\t\t\texitcode = 2\n\t\t\treturn\n\t\t}\n\n\t\tcache.Init(os.Getenv(\"POSH_SHELL\"))\n\n\t\terr := setConfigFlag()\n\t\tif err != nil {\n\t\t\texitcode = 666\n\t\t\tfmt.Println(err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tcfg := config.Load(configFlag)\n\n\t\tvalidateExportFormat := func() error {\n\t\t\tformat = strings.ToLower(format)\n\t\t\tswitch format {\n\t\t\tcase config.JSON, config.JSONC:\n\t\t\t\tformat = config.JSON\n\t\t\tcase config.TOML, config.TML:\n\t\t\t\tformat = config.TOML\n\t\t\tcase config.YAML, config.YML:\n\t\t\t\tformat = config.YAML\n\t\t\tdefault:\n\t\t\t\tformats := []string{config.JSON, config.JSONC, config.TOML, config.TML, config.YAML, config.YML}\n\t\t\t\t// usage error\n\t\t\t\tfmt.Printf(\"export format must be one of these: %s\\n\", strings.Join(formats, \", \"))\n\t\t\t\texitcode = 2\n\t\t\t\treturn errors.New(\"invalid export format\")\n\t\t\t}\n\n\t\t\treturn nil\n\t\t}\n\n\t\tif len(format) != 0 {\n\t\t\tif err := validateExportFormat(); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tif output == \"\" {\n\t\t\tfmt.Print(cfg.Export(format))\n\t\t\treturn\n\t\t}\n\n\t\tcfg.Source = cleanOutputPath(output)\n\n\t\tif format == \"\" {\n\t\t\tformat = strings.TrimPrefix(filepath.Ext(output), \".\")\n\t\t\tif err := validateExportFormat(); err != nil {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tcfg.Write(format)\n\t},\n}\n\nfunc cleanOutputPath(output string) string {\n\toutput = path.ReplaceTildePrefixWithHomeDir(output)\n\n\tif !filepath.IsAbs(output) {\n\t\tif absPath, err := filepath.Abs(output); err == nil {\n\t\t\toutput = absPath\n\t\t}\n\t}\n\n\treturn filepath.Clean(output)\n}\n\nfunc init() {\n\texportCmd.Flags().StringVarP(&format, \"format\", \"f\", \"json\", \"config format to migrate to\")\n\texportCmd.Flags().StringVarP(&output, \"output\", \"o\", \"\", \"config file to export to\")\n\tconfigCmd.AddCommand(exportCmd)\n}\n"
  },
  {
    "path": "src/cli/config_export_image.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/image\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tauthor            string\n\tcolorSettingsFile string\n\tbgColor           string\n\toutputImage       string\n)\n\n// imageCmd represents the image command\nvar imageCmd = &cobra.Command{\n\tUse:   \"image\",\n\tShort: \"Export your config to an image\",\n\tLong: `Export your config to an image.\n\nYou can tweak the output by using additional flags:\n\n- cursor-padding: the padding of the prompt cursor\n- rprompt-offset: the offset of the right prompt\n- settings: JSON file with overrides\n\nExample usage:\n\n> oh-my-posh config export image --config ~/myconfig.omp.json\n\nExports the config to an image file called myconfig.png in the current working directory.\n\n> oh-my-posh config export image --config ~/myconfig.omp.json --output ~/mytheme.png\n\nExports the config to an image file ~/mytheme.png.\n\n> oh-my-posh config export image --config ~/myconfig.omp.json --settings ~/.image.settings.json\n\nExports the config to an image file using customized output settings.`,\n\tArgs: cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tcache.Init(os.Getenv(\"POSH_SHELL\"))\n\n\t\terr := setConfigFlag()\n\t\tif err != nil {\n\t\t\texitcode = 666\n\t\t\tfmt.Println(err.Error())\n\t\t\treturn\n\t\t}\n\n\t\tcfg := config.Load(configFlag)\n\n\t\tflags := &runtime.Flags{\n\t\t\tConfigPath:    cfg.Source,\n\t\t\tShell:         shell.GENERIC,\n\t\t\tTerminalWidth: 120,\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(flags)\n\n\t\ttemplate.Init(env, cfg.Var, cfg.Maps)\n\n\t\tdefer func() {\n\t\t\ttemplate.SaveCache()\n\t\t\tcache.Close()\n\t\t}()\n\n\t\t// set sane defaults for things we don't print\n\t\tcfg.ConsoleTitleTemplate = \"\"\n\t\tcfg.PWD = \"\"\n\t\tcfg.ShellIntegration = false\n\n\t\tterminal.Init(shell.GENERIC)\n\t\tterminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()\n\t\tterminal.Colors = cfg.MakeColors(env)\n\n\t\teng := &prompt.Engine{\n\t\t\tConfig: cfg,\n\t\t\tEnv:    env,\n\t\t}\n\n\t\tsettings, err := image.LoadSettings(colorSettingsFile)\n\t\tif err != nil {\n\t\t\tsettings = &image.Settings{\n\t\t\t\tColors:          image.NewColors(),\n\t\t\t\tAuthor:          author,\n\t\t\t\tBackgroundColor: bgColor,\n\t\t\t}\n\t\t}\n\n\t\tif settings.Colors == nil {\n\t\t\tsettings.Colors = image.NewColors()\n\t\t}\n\n\t\tif settings.Cursor == \"\" {\n\t\t\tsettings.Cursor = \"_\"\n\t\t}\n\n\t\tprimaryPrompt := eng.Primary()\n\n\t\timageCreator := &image.Renderer{\n\t\t\tAnsiString: primaryPrompt,\n\t\t\tSettings:   *settings,\n\t\t}\n\n\t\tif outputImage != \"\" {\n\t\t\timageCreator.Path = cleanOutputPath(outputImage)\n\t\t}\n\n\t\terr = imageCreator.Init(env)\n\t\tif err != nil {\n\t\t\tfmt.Print(err.Error())\n\t\t\treturn\n\t\t}\n\n\t\terr = imageCreator.SavePNG()\n\t\tif err != nil {\n\t\t\tfmt.Print(err.Error())\n\t\t}\n\t},\n}\n\nfunc init() {\n\timageCmd.Flags().StringVar(&author, \"author\", \"\", \"config author\")\n\timageCmd.Flags().StringVar(&bgColor, \"background-color\", \"\", \"image background color\")\n\timageCmd.Flags().StringVarP(&outputImage, \"output\", \"o\", \"\", \"image file (.png) to export to\")\n\timageCmd.Flags().StringVar(&colorSettingsFile, \"settings\", \"\", \"color settings file to override ANSI color codes and metadata\")\n\n\t// deprecated flags\n\t_ = imageCmd.Flags().MarkHidden(\"author\")\n\t_ = imageCmd.Flags().MarkHidden(\"background-color\")\n\n\texportCmd.AddCommand(imageCmd)\n}\n\nfunc setConfigFlag() error {\n\tif configFlag != \"\" {\n\t\treturn nil\n\t}\n\n\tconfigPath, OK := cache.Get[string](cache.Session, config.SourceKey)\n\tif !OK {\n\t\treturn fmt.Errorf(\"no config found in session cache, please provide a config using the --config flag\")\n\t}\n\n\tconfigFlag = configPath\n\treturn nil\n}\n"
  },
  {
    "path": "src/cli/debug.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// debugCmd represents the debug command\nvar (\n\tdebugCmd  = createDebugCmd()\n\tstartTime = time.Now()\n)\n\nfunc init() {\n\tRootCmd.AddCommand(debugCmd)\n}\n\nfunc createDebugCmd() *cobra.Command {\n\tdebugCmd := &cobra.Command{\n\t\tUse:   \"debug\",\n\t\tShort: \"Print the prompt in debug mode\",\n\t\tLong:  \"Print the prompt in debug mode.\",\n\t\tRun: func(_ *cobra.Command, _ []string) {\n\t\t\tstartTime := time.Now()\n\n\t\t\tlog.Enable(plain)\n\n\t\t\tflags := &runtime.Flags{\n\t\t\t\tDebug: true,\n\t\t\t\tPWD:   pwd,\n\t\t\t\tShell: shell.GENERIC,\n\t\t\t\tPlain: plain,\n\t\t\t}\n\n\t\t\tenv := &runtime.Terminal{}\n\t\t\tenv.Init(flags)\n\n\t\t\tcache.Init(os.Getenv(\"POSH_SHELL\"))\n\n\t\t\tcfg := getDebugConfig(configFlag)\n\n\t\t\ttemplate.Init(env, cfg.Var, cfg.Maps)\n\n\t\t\tdefer func() {\n\t\t\t\ttemplate.SaveCache()\n\t\t\t\tcache.Close()\n\t\t\t}()\n\n\t\t\tterminal.Init(shell.GENERIC)\n\t\t\tterminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()\n\t\t\tterminal.Colors = cfg.MakeColors(env)\n\t\t\tterminal.Plain = plain\n\n\t\t\teng := &prompt.Engine{\n\t\t\t\tConfig: cfg,\n\t\t\t\tEnv:    env,\n\t\t\t\tPlain:  plain,\n\t\t\t}\n\n\t\t\tfmt.Print(eng.PrintDebug(startTime, build.Version))\n\t\t},\n\t}\n\n\tdebugCmd.Flags().StringVar(&pwd, \"pwd\", \"\", \"current working directory\")\n\n\t// Deprecated flags, should be kept to avoid breaking CLI integration.\n\tdebugCmd.Flags().StringVar(&shellName, \"shell\", \"\", \"the shell to print for\")\n\n\t// Hide flags that are deprecated or for internal use only.\n\t_ = debugCmd.Flags().MarkHidden(\"shell\")\n\n\treturn debugCmd\n}\n\nfunc getDebugConfig(configpath string) *config.Config {\n\tif len(configpath) != 0 {\n\t\treturn config.Load(configpath)\n\t}\n\n\treload, _ := cache.Get[bool](cache.Device, config.RELOAD)\n\treturn config.Get(configpath, reload)\n}\n"
  },
  {
    "path": "src/cli/disable.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// disableCmd represents the disable command\nvar disableCmd = &cobra.Command{\n\tUse:       fmt.Sprintf(toggleUse, \"disable\"),\n\tShort:     \"Disable a feature\",\n\tLong:      fmt.Sprintf(toggleLong, \"Disable\"),\n\tValidArgs: toggleArgs,\n\tArgs:      NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\t\ttoggleFeature(cmd, args[0], false)\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(disableCmd)\n}\n"
  },
  {
    "path": "src/cli/edit.go",
    "content": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"strings\"\n)\n\nfunc editFileWithEditor(file string) int {\n\teditor := strings.TrimSpace(os.Getenv(\"EDITOR\"))\n\tif editor == \"\" {\n\t\tfmt.Println(`no editor specified in the environment variable \"EDITOR\"`)\n\t\treturn 1\n\t}\n\n\teditor = strings.TrimSpace(editor)\n\targs := strings.Split(editor, \" \")\n\teditor = args[0]\n\targs = append(args[1:], file)\n\n\tctx := context.Background()\n\tcmd := exec.CommandContext(ctx, editor, args...)\n\n\tcmd.Stdin = os.Stdin\n\tcmd.Stdin = os.Stdin\n\tcmd.Stdout = os.Stdout\n\tcmd.Stderr = os.Stderr\n\n\tif err := cmd.Run(); err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn 1\n\t}\n\n\treturn 0\n}\n"
  },
  {
    "path": "src/cli/enable.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\ttoggleHelpText = `%s one of the following features:\n`\n\ttoggleArgs = []string{\n\t\tconfig.UPGRADENOTICE,\n\t\tconfig.AUTOUPGRADE,\n\t\tconfig.RELOAD,\n\t}\n\ttoggleUse  = fmt.Sprintf(\"%%s [%s]\", strings.Join(toggleArgs, \"|\"))\n\ttoggleLong = strings.Join(append([]string{toggleHelpText}, toggleArgs...), \"\\n- \")\n)\n\n// enableCmd represents the enable command\nvar enableCmd = &cobra.Command{\n\tUse:       fmt.Sprintf(toggleUse, \"enable\"),\n\tShort:     \"Enable a feature\",\n\tLong:      fmt.Sprintf(toggleLong, \"Enable\"),\n\tValidArgs: toggleArgs,\n\tArgs:      NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\t\ttoggleFeature(cmd, args[0], true)\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(enableCmd)\n}\n\nfunc toggleFeature(cmd *cobra.Command, feature string, enable bool) {\n\tif feature == \"\" {\n\t\t_ = cmd.Help()\n\t\treturn\n\t}\n\n\tcache.Init(os.Getenv(\"POSH_SHELL\"), cache.Persist)\n\tcache.Set(cache.Device, feature, enable, cache.INFINITE)\n\tcache.Close()\n}\n"
  },
  {
    "path": "src/cli/font/download.go",
    "content": "package font\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\thttplib \"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/progress\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nfunc Download(fontURL string) ([]byte, error) {\n\tif zipPath, OK := cache.Get[string](cache.Device, fontURL); OK {\n\t\tif b, err := os.ReadFile(zipPath); err == nil {\n\t\t\treturn b, nil\n\t\t}\n\t}\n\n\t// validate if we have a local file\n\tu, err := url.Parse(fontURL)\n\tif err != nil || u.Scheme != \"https\" {\n\t\treturn nil, errors.New(\"font path must be a valid URL\")\n\t}\n\n\tvar b []byte\n\tif b, err = getRemoteFile(fontURL); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !isZipFile(b) {\n\t\treturn nil, fmt.Errorf(\"%s is not a valid zip file\", fontURL)\n\t}\n\n\tfileName := path.Base(fontURL)\n\n\tzipPath := filepath.Join(os.TempDir(), fileName)\n\ttempFile, err := os.Create(zipPath)\n\tdefer func() {\n\t\t_ = tempFile.Close()\n\t}()\n\n\tif err != nil {\n\t\treturn b, nil\n\t}\n\n\t_, err = tempFile.Write(b)\n\tif err != nil {\n\t\treturn b, nil\n\t}\n\n\tcache.Set(cache.Device, fontURL, zipPath, cache.ONEDAY)\n\n\treturn b, nil\n}\n\nfunc isZipFile(data []byte) bool {\n\tcontentType := httplib.DetectContentType(data)\n\treturn contentType == \"application/zip\"\n}\n\nfunc getRemoteFile(location string) (data []byte, err error) {\n\treq, err := httplib.NewRequestWithContext(context.Background(), \"GET\", location, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tresp, err := http.HTTPClient.Do(req)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != httplib.StatusOK {\n\t\treturn data, fmt.Errorf(\"failed to download zip file: %s\\n→ %s\", resp.Status, location)\n\t}\n\n\treader := progress.NewReader(resp.Body, resp.ContentLength, program)\n\n\tdata, err = io.ReadAll(reader)\n\tif err != nil {\n\t\treturn\n\t}\n\n\treturn\n}\n"
  },
  {
    "path": "src/cli/font/dsc.go",
    "content": "package font\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Resource struct {\n\tdsc.Resource[*Font]\n}\n\nfunc DSC() *Resource {\n\treturn &Resource{\n\t\tResource: dsc.Resource[*Font]{},\n\t}\n}\n\nfunc (s *Resource) Apply(schema string) error {\n\treturn s.Resource.Apply(schema)\n}\n\nfunc (s *Resource) Add(name string) {\n\tif IsLocalZipFile(name) {\n\t\tlog.Debug(\"Skipping local zip file font:\", name)\n\t\treturn\n\t}\n\n\ts.Resource.Add(&Font{\n\t\tName: name,\n\t})\n}\n"
  },
  {
    "path": "src/cli/font/font.go",
    "content": "// Derived from https://github.com/Crosse/font-install\n// Copyright 2020 Seth Wright <seth@crosse.org>\npackage font\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/ConradIrwin/font/sfnt\"\n)\n\nfunc init() {\n\tgob.Register([]*Font{})\n\tgob.Register([]*Asset{})\n}\n\n// Font describes a font file and the various metadata associated with it.\ntype Font struct {\n\tName     string                 `json:\"name,omitempty\" jsonschema:\"title=Font name,description=The name of the font\"`\n\tFamily   string                 `json:\"-\"`\n\tFileName string                 `json:\"-\"`\n\tMetadata map[sfnt.NameID]string `json:\"-\"`\n\tData     []byte                 `json:\"-\"`\n}\n\nfunc (f *Font) Apply() error {\n\t_, err := downloadAndInstall(f.Name, \"\")\n\treturn err\n}\n\n// downloadAndInstall resolves a font by name or URL, downloads it, and installs it.\n// It returns the resolved font name and any error encountered.\nfunc downloadAndInstall(font, zipFolder string) (string, error) {\n\tasset, err := ResolveFontAsset(font)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif asset.Folder != \"\" && zipFolder == \"\" {\n\t\tzipFolder = asset.Folder\n\t}\n\n\tzipFile, err := Download(asset.URL)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t_, err = InstallZIP(zipFile, zipFolder)\n\treturn asset.Name, err\n}\n\nfunc (f *Font) Equal(font *Font) bool {\n\tif font == nil {\n\t\treturn false\n\t}\n\n\treturn f.Name == font.Name\n}\n\nfunc (f *Font) Resolve() (*Font, bool) {\n\treturn nil, false\n}\n\n// fontExtensions is a list of file extensions that denote fonts.\n// Only files ending with these extensions will be installed.\nvar fontExtensions = map[string]bool{\n\t\".otf\": true,\n\t\".ttf\": true,\n}\n\n// newFont creates a newFont Font struct.\n// fileName is the font's file name, and data is a byte slice containing the font file data.\n// It returns a FontData struct describing the font, or an error.\nfunc newFont(fileName string, data []byte) (*Font, error) {\n\tif _, ok := fontExtensions[strings.ToLower(path.Ext(fileName))]; !ok {\n\t\treturn nil, fmt.Errorf(\"not a font: %v\", fileName)\n\t}\n\n\tfont := &Font{\n\t\tFileName: fileName,\n\t\tMetadata: make(map[sfnt.NameID]string),\n\t\tData:     data,\n\t}\n\n\tfontData, err := sfnt.Parse(bytes.NewReader(font.Data))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif !fontData.HasTable(sfnt.TagName) {\n\t\treturn nil, fmt.Errorf(\"font %v has no name table\", fileName)\n\t}\n\n\tnameTable, err := fontData.NameTable()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, nameEntry := range nameTable.List() {\n\t\tfont.Metadata[nameEntry.NameID] = nameEntry.String()\n\t}\n\n\tfont.Name = font.Metadata[sfnt.NameFull]\n\tfont.Family = font.Metadata[sfnt.NamePreferredFamily]\n\n\tif font.Family == \"\" {\n\t\tif v, ok := font.Metadata[sfnt.NameFontFamily]; ok {\n\t\t\tfont.Family = v\n\t\t}\n\t}\n\n\tif font.Name == \"\" {\n\t\tfont.Name = fileName\n\t}\n\n\treturn font, nil\n}\n"
  },
  {
    "path": "src/cli/font/fonts.go",
    "content": "package font\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\thttplib \"net/http\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nconst (\n\tCascadiaCodeMS = \"CascadiaCode (MS)\"\n)\n\ntype release struct {\n\tAssets []*Asset `json:\"assets\"`\n}\n\ntype Asset struct {\n\tName   string `json:\"name\"`\n\tURL    string `json:\"browser_download_url\"`\n\tState  string `json:\"state\"`\n\tFolder string `json:\"folder\"`\n}\n\nfunc (a Asset) FilterValue() string { return a.Name }\n\nfunc IsLocalZipFile(name string) bool {\n\treturn !strings.HasPrefix(name, \"https\") && strings.HasSuffix(name, \".zip\")\n}\n\nfunc ResolveFontAsset(font string) (*Asset, error) {\n\tif strings.HasPrefix(font, \"https\") {\n\t\treturn &Asset{URL: font}, nil\n\t}\n\n\tfonts, err := fonts()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar asset *Asset\n\tfor _, f := range fonts {\n\t\tif !strings.EqualFold(font, f.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\tasset = f\n\t\tbreak\n\t}\n\n\tif asset == nil {\n\t\treturn nil, fmt.Errorf(\"no matching font found\")\n\t}\n\n\treturn asset, nil\n}\n\nfunc fonts() ([]*Asset, error) {\n\tif assets, err := getCachedFontData(); err == nil {\n\t\treturn assets, nil\n\t}\n\n\tassets, err := fetchFontAssets(\"ryanoasis/nerd-fonts\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcascadiaCode, err := CascadiaCode()\n\tif err == nil {\n\t\tassets = append(assets, cascadiaCode)\n\t}\n\n\tsort.Slice(assets, func(i, j int) bool { return assets[i].Name < assets[j].Name })\n\n\tcache.Set(cache.Device, cache.FONTLISTCACHE, assets, cache.ONEDAY)\n\n\treturn assets, nil\n}\n\nfunc getCachedFontData() ([]*Asset, error) {\n\tlist, OK := cache.Get[[]*Asset](cache.Device, cache.FONTLISTCACHE)\n\tif !OK {\n\t\treturn nil, errors.New(\"cache not found\")\n\t}\n\n\treturn list, nil\n}\n\nfunc CascadiaCode() (*Asset, error) {\n\tassets, err := fetchFontAssets(\"microsoft/cascadia-code\")\n\tif err != nil || len(assets) != 1 {\n\t\treturn nil, errors.New(\"no assets found\")\n\t}\n\n\treturn &Asset{\n\t\tName:   CascadiaCodeMS,\n\t\tURL:    assets[0].URL,\n\t\tFolder: \"ttf/\",\n\t}, nil\n}\n\nfunc fetchFontAssets(repo string) ([]*Asset, error) {\n\tctx, cancelF := context.WithTimeout(context.Background(), time.Second*time.Duration(20))\n\tdefer cancelF()\n\n\trepoURL := \"https://api.github.com/repos/\" + repo + \"/releases/latest\"\n\treq, err := httplib.NewRequestWithContext(ctx, \"GET\", repoURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq.Header.Add(\"Accept\", \"application/vnd.github.v3+json\")\n\tresponse, err := http.HTTPClient.Do(req)\n\tif err != nil || response.StatusCode != httplib.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to get %s release\", repo)\n\t}\n\n\tdefer response.Body.Close()\n\n\tvar release release\n\terr = json.NewDecoder(response.Body).Decode(&release)\n\tif err != nil {\n\t\treturn nil, errors.New(\"failed to parse nerd fonts release\")\n\t}\n\n\tvar fonts []*Asset\n\tfor _, asset := range release.Assets {\n\t\tif asset.State == \"uploaded\" && strings.HasSuffix(asset.Name, \".zip\") {\n\t\t\tasset.Name = strings.TrimSuffix(asset.Name, \".zip\")\n\t\t\tfonts = append(fonts, asset)\n\t\t}\n\t}\n\n\treturn fonts, nil\n}\n"
  },
  {
    "path": "src/cli/font/install.go",
    "content": "// Derived from https://github.com/Crosse/font-install\n// Copyright 2020 Seth Wright <seth@crosse.org>\npackage font\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"io\"\n\t\"path\"\n\tstdruntime \"runtime\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n)\n\nfunc contains[S ~[]E, E comparable](s S, e E) bool {\n\treturn slices.Contains(s, e)\n}\n\nfunc InstallZIP(data []byte, folder string) ([]string, error) {\n\tvar families []string\n\tbytesReader := bytes.NewReader(data)\n\n\tzipReader, err := zip.NewReader(bytesReader, int64(bytesReader.Len()))\n\tif err != nil {\n\t\treturn families, err\n\t}\n\n\tfonts := make(map[string]*Font)\n\n\tfor _, file := range zipReader.File {\n\t\t// prevent zipslip attacks\n\t\t// https://security.snyk.io/research/zip-slip-vulnerability\n\t\t// skip folders\n\t\tif strings.Contains(file.Name, \"..\") || strings.HasSuffix(file.Name, \"/\") {\n\t\t\tcontinue\n\t\t}\n\n\t\tfontFileName := path.Base(file.Name)\n\t\tfontRelativeFileName := strings.TrimPrefix(file.Name, folder)\n\n\t\t// do not install fonts that are not in the specified installation folder\n\t\tif fontFileName != fontRelativeFileName {\n\t\t\tcontinue\n\t\t}\n\n\t\tfontReader, err := file.Open()\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tdefer fontReader.Close()\n\n\t\tfontBytes, err := io.ReadAll(fontReader)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfont, err := newFont(fontFileName, fontBytes)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif _, found := fonts[font.Name]; !found {\n\t\t\tfonts[font.Name] = font\n\t\t\tcontinue\n\t\t}\n\n\t\t// prefer .ttf files over other file types when we have a duplicate\n\t\tfirst := strings.ToLower(path.Ext(fonts[font.Name].FileName))\n\t\tsecond := strings.ToLower(path.Ext(font.FileName))\n\t\tif first != second && second == \".ttf\" {\n\t\t\tfonts[font.Name] = font\n\t\t}\n\t}\n\n\tfor _, font := range fonts {\n\t\tif err = install(font); err != nil {\n\t\t\tlog.Error(err)\n\t\t\tcontinue\n\t\t}\n\n\t\tif found := contains(families, font.Family); !found {\n\t\t\tfamilies = append(families, font.Family)\n\t\t}\n\t}\n\n\t// Update the font cache when installing fonts on Linux\n\tif stdruntime.GOOS == runtime.LINUX || stdruntime.GOOS == runtime.DARWIN {\n\t\t_, _ = cmd.Run(\"fc-cache\", \"-f\")\n\t}\n\n\tslices.Sort(families)\n\n\treturn families, nil\n}\n"
  },
  {
    "path": "src/cli/font/install_darwin.go",
    "content": "// Derived from https://github.com/Crosse/font-install\n// Copyright 2020 Seth Wright <seth@crosse.org>\npackage font\n\nimport (\n\t\"os\"\n\t\"path\"\n)\n\nvar FontsDir = path.Join(os.Getenv(\"HOME\"), \"Library\", \"Fonts\")\n\nfunc install(font *Font) error {\n\t// On darwin/OSX, the user's fonts directory is ~/Library/Fonts,\n\t// and fonts should be installed directly into that path;\n\t// i.e., not in subfolders.\n\tfullPath := path.Join(FontsDir, path.Base(font.FileName))\n\n\tif err := os.MkdirAll(path.Dir(fullPath), 0700); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(fullPath, font.Data, 0644)\n}\n"
  },
  {
    "path": "src/cli/font/install_unix.go",
    "content": "//go:build !windows && !darwin\n\n// Derived from https://github.com/Crosse/font-install\n// Copyright 2020 Seth Wright <seth@crosse.org>\npackage font\n\nimport (\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n)\n\nvar (\n\tfontsDir       = path.Join(os.Getenv(\"HOME\"), \"/.local/share/fonts\")\n\tsystemFontsDir = \"/usr/share/fonts\"\n)\n\nfunc install(font *Font) error {\n\t// If we're running as root, install the font system-wide.\n\ttargetDir := fontsDir\n\tif os.Geteuid() == 0 {\n\t\ttargetDir = systemFontsDir\n\t}\n\n\t// On Linux, fontconfig can understand subdirectories. So, to keep the\n\t// font directory clean, install all font files for a particular font\n\t// family into a subdirectory named after the family (with hyphens instead\n\t// of spaces).\n\tfullPath := path.Join(targetDir,\n\t\tstrings.ToLower(strings.ReplaceAll(font.Family, \" \", \"-\")),\n\t\tpath.Base(font.FileName))\n\n\tif err := os.MkdirAll(path.Dir(fullPath), 0700); err != nil {\n\t\treturn err\n\t}\n\n\treturn os.WriteFile(fullPath, font.Data, 0644)\n}\n"
  },
  {
    "path": "src/cli/font/install_windows.go",
    "content": "package font\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"golang.org/x/sys/windows/registry\"\n)\n\n// https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-addfontresourcea\n\nconst (\n\tWM_FONTCHANGE  = 0x001D\n\tHWND_BROADCAST = 0xFFFF\n)\n\nfunc install(font *Font) error {\n\t// To install a font on Windows:\n\t//  - Copy the file to the fonts directory\n\t//  - Add registry entry\n\t//  - Call AddFontResourceW to set the font\n\tfontsDir := filepath.Join(os.Getenv(\"USERPROFILE\"), \"AppData\", \"Local\", \"Microsoft\", \"Windows\", \"Fonts\")\n\n\tlog.Debugf(\"installing font %s to %s\", font.FileName, fontsDir)\n\n\t// check if the Fonts folder exists, if not, create it\n\tif _, err := os.Stat(fontsDir); os.IsNotExist(err) {\n\t\tif err = os.MkdirAll(fontsDir, 0755); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to create fonts directory: %s\", err.Error())\n\t\t}\n\t}\n\n\tlog.Debug(\"fonts directory exists, proceeding with installation\")\n\n\tfullPath := filepath.Join(fontsDir, font.FileName)\n\t// validate if the font is already installed, remove it in case it is\n\tif _, err := os.Stat(fullPath); err == nil {\n\t\tlog.Debugf(\"font %s already exists, removing it\", fullPath)\n\t\tif err = os.Remove(fullPath); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to remove existing font file: %s\", err.Error())\n\t\t}\n\t}\n\n\tlog.Debugf(\"writing font file to %s\", fullPath)\n\n\terr := os.WriteFile(fullPath, font.Data, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to write font file: %s\", err.Error())\n\t}\n\n\tlog.Debug(\"font file written successfully, proceeding with registry entry\")\n\n\t// Add registry entry\n\treg := registry.CURRENT_USER\n\tregValue := fullPath\n\n\tlog.Debug(\"opening HKEY_CURRENT_USER for writing (SOFTWARE\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\Fonts)\")\n\n\tk, _, err := registry.CreateKey(reg, `SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts`, registry.WRITE)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\t// If this fails, remove the font file as well.\n\t\tif nexterr := os.Remove(fullPath); nexterr != nil {\n\t\t\tlog.Error(nexterr)\n\t\t\treturn errors.New(\"unable to delete font file after registry key open error\")\n\t\t}\n\n\t\treturn errors.New(\"unable to open HKEY_CURRENT_USER\")\n\t}\n\n\tdefer func() {\n\t\terr := k.Close()\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t}()\n\n\tfontName := fmt.Sprintf(\"%v (TrueType)\", font.Name)\n\tvar alreadyInstalled, newFontType bool\n\n\tlog.Debugf(\"validating if font %s is already installed\", fontName)\n\n\t// check if we already had this key set\n\toldFullPath, _, err := k.GetStringValue(fontName)\n\tif err == nil {\n\t\tlog.Debugf(\"font %s is already installed with path %s\", fontName, oldFullPath)\n\t\talreadyInstalled = true\n\t\tnewFontType = oldFullPath != fullPath\n\t}\n\n\tif !alreadyInstalled {\n\t\tlog.Debug(\"font is not registered, adding to registry\")\n\t\tif err := k.SetStringValue(fontName, fullPath); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tlog.Debug(\"font registry entry added successfully\")\n\t}\n\n\t// do not call AddFontResourceW if the font was already installed\n\tif alreadyInstalled && !newFontType {\n\t\tlog.Debugf(\"font %s is already installed, skipping AddFontResourceW\", fontName)\n\t\treturn nil\n\t}\n\n\tgdi32 := syscall.NewLazyDLL(\"gdi32.dll\")\n\taddFontResourceW := gdi32.NewProc(\"AddFontResourceW\")\n\n\t// remove the old font resource in case we have a new font type with the same name\n\tif newFontType {\n\t\tlog.Debug(\"removing old font resource before adding new one\")\n\t\tfontPtr, err := syscall.UTF16PtrFromString(oldFullPath)\n\t\tif err == nil {\n\t\t\tremoveFontResourceW := gdi32.NewProc(\"RemoveFontResourceW\")\n\t\t\t_, _, _ = removeFontResourceW.Call(uintptr(unsafe.Pointer(fontPtr)))\n\t\t}\n\t}\n\n\tif err = k.SetStringValue(fontName, regValue); err != nil {\n\t\tlog.Error(err)\n\t\t// If this fails, remove the font file as well.\n\t\tif nexterr := os.Remove(fullPath); nexterr != nil {\n\t\t\treturn errors.New(\"unable to delete font file after registry key set error\")\n\t\t}\n\n\t\treturn fmt.Errorf(\"unable to set registry value: %s\", err.Error())\n\t}\n\n\tfontPtr, err := syscall.UTF16PtrFromString(fullPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tret, _, _ := addFontResourceW.Call(uintptr(unsafe.Pointer(fontPtr)))\n\tif ret == 0 {\n\t\treturn errors.New(\"unable to add font resource using AddFontResourceW\")\n\t}\n\n\tlog.Debug(\"font resource added successfully\")\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/cli/font/tui.go",
    "content": "package font\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/charmbracelet/bubbles/list\"\n\tprogress_ \"github.com/charmbracelet/bubbles/progress\"\n\t\"github.com/charmbracelet/bubbles/spinner\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/charmbracelet/lipgloss\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/progress\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nvar (\n\tprogram *tea.Program\n)\n\nconst listHeight = 14\n\nvar (\n\titemStyle         = lipgloss.NewStyle().PaddingLeft(3)\n\tselectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color(\"170\"))\n\tpaginationStyle   = list.DefaultStyles().PaginationStyle.PaddingLeft(3)\n\thelpStyle         = lipgloss.NewStyle().PaddingLeft(3).PaddingBottom(1)\n\ttextStyle         = lipgloss.NewStyle().Margin(1, 0, 2, 2)\n)\n\ntype loadMsg []*Asset\n\ntype zipMsg []byte\n\ntype successMsg []string\n\ntype errMsg error\n\ntype state int\n\ntype itemDelegate struct{}\n\nfunc (d itemDelegate) Height() int                             { return 1 }\nfunc (d itemDelegate) Spacing() int                            { return 0 }\nfunc (d itemDelegate) Update(_ tea.Msg, _ *list.Model) tea.Cmd { return nil }\nfunc (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) { //nolint: gocritic\n\ti, ok := listItem.(*Asset)\n\tif !ok {\n\t\treturn\n\t}\n\n\tfn := itemStyle.Render\n\tif index == m.Index() {\n\t\tfn = func(s ...string) string {\n\t\t\treturn selectedItemStyle.Render(\"•\" + strings.Join(s, \" \"))\n\t\t}\n\t}\n\n\tfmt.Fprint(w, fn(i.Name))\n}\n\nconst (\n\tgetFonts state = iota\n\tselectFont\n\tdownloadFont\n\tunzipFont\n\tinstallFont\n\tquit\n\tdone\n)\n\ntype main struct {\n\terr      error\n\tlist     *list.Model\n\tspinner  *spinner.Model\n\tprogress *progress.Model\n\tAsset\n\tfamilies []string\n\tstate    state\n}\n\nfunc (m *main) buildFontList(nerdFonts []*Asset) {\n\tvar items []list.Item\n\tfor _, font := range nerdFonts {\n\t\titems = append(items, font)\n\t}\n\n\tconst defaultWidth = 20\n\n\tl := list.New(items, itemDelegate{}, defaultWidth, listHeight)\n\tl.Title = \"Select font\"\n\tl.SetShowStatusBar(false)\n\tl.SetFilteringEnabled(false)\n\tl.Styles.PaginationStyle = paginationStyle\n\tl.Styles.HelpStyle = helpStyle\n\n\tm.list = &l\n}\n\nfunc getFontsList() {\n\tfonts, err := fonts()\n\tif err != nil {\n\t\tprogram.Send(errMsg(err))\n\t\treturn\n\t}\n\n\tprogram.Send(loadMsg(fonts))\n}\n\nfunc downloadFontZip(location string) {\n\tzipFile, err := Download(location)\n\tif err != nil {\n\t\tprogram.Send(errMsg(err))\n\t\treturn\n\t}\n\n\tprogram.Send(zipMsg(zipFile))\n}\n\nfunc installLocalFontZIP(m *main) {\n\tdata, err := os.ReadFile(m.URL)\n\tif err != nil {\n\t\tprogram.Send(errMsg(err))\n\t\treturn\n\t}\n\n\tinstallFontZIP(data, m)\n}\n\nfunc installFontZIP(zipFile []byte, m *main) {\n\tfamilies, err := InstallZIP(zipFile, m.Folder)\n\tif err != nil {\n\t\tprogram.Send(errMsg(err))\n\t\treturn\n\t}\n\n\tprogram.Send(successMsg(families))\n}\n\nfunc (m *main) Init() tea.Cmd {\n\tm.progress = progress.NewModel()\n\n\ts := spinner.New()\n\tm.spinner = &s\n\n\tif len(m.URL) != 0 && !IsLocalZipFile(m.URL) {\n\t\tm.state = downloadFont\n\n\t\tasset, err := ResolveFontAsset(m.URL)\n\t\tif err != nil {\n\t\t\tm.err = err\n\t\t\treturn tea.Quit\n\t\t}\n\n\t\tm.Asset = *asset\n\n\t\tdefer func() {\n\t\t\tgo downloadFontZip(asset.URL)\n\t\t}()\n\n\t\tm.spinner.Spinner = spinner.Globe\n\t\treturn m.spinner.Tick\n\t}\n\n\tdefer func() {\n\t\tif IsLocalZipFile(m.URL) {\n\t\t\tgo installLocalFontZIP(m)\n\t\t\treturn\n\t\t}\n\n\t\tgo getFontsList()\n\t}()\n\n\tm.spinner.Spinner = spinner.Dot\n\tm.spinner.Style = lipgloss.NewStyle().Foreground(lipgloss.Color(\"170\"))\n\tm.state = getFonts\n\n\tif IsLocalZipFile(m.URL) {\n\t\tm.state = unzipFont\n\t}\n\n\treturn m.spinner.Tick\n}\n\nfunc (m *main) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tswitch msg := msg.(type) {\n\tcase loadMsg:\n\t\tm.state = selectFont\n\t\tm.buildFontList(msg)\n\t\treturn m, nil\n\n\tcase tea.WindowSizeMsg:\n\t\tif m.list == nil {\n\t\t\treturn m, nil\n\t\t}\n\t\tm.list.SetWidth(msg.Width)\n\t\treturn m, nil\n\n\tcase tea.KeyMsg:\n\t\tswitch keypress := msg.String(); keypress {\n\t\tcase \"ctrl+c\", \"q\", \"esc\":\n\t\t\tm.state = quit\n\t\t\treturn m, tea.Quit\n\n\t\tcase \"enter\":\n\t\t\tif len(m.URL) != 0 || m.list == nil || m.list.SelectedItem() == nil {\n\t\t\t\treturn m, nil\n\t\t\t}\n\n\t\t\tvar font *Asset\n\t\t\tvar ok bool\n\n\t\t\tif font, ok = m.list.SelectedItem().(*Asset); !ok {\n\t\t\t\tm.err = fmt.Errorf(\"no font selected\")\n\t\t\t\treturn m, tea.Quit\n\t\t\t}\n\n\t\t\tm.state = downloadFont\n\t\t\tm.Asset = *font\n\n\t\t\tdefer func() {\n\t\t\t\tgo downloadFontZip(font.URL)\n\t\t\t}()\n\n\t\t\tm.spinner.Spinner = spinner.Globe\n\t\t\treturn m, m.spinner.Tick\n\n\t\tcase \"up\", \"k\":\n\t\t\tif m.list != nil {\n\t\t\t\tif m.list.Index() == 0 {\n\t\t\t\t\tm.list.Select(len(m.list.Items()) - 1)\n\t\t\t\t} else {\n\t\t\t\t\tm.list.Select(m.list.Index() - 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn m, nil\n\n\t\tcase \"down\", \"j\":\n\t\t\tif m.list != nil {\n\t\t\t\tif m.list.Index() == len(m.list.Items())-1 {\n\t\t\t\t\tm.list.Select(0)\n\t\t\t\t} else {\n\t\t\t\t\tm.list.Select(m.list.Index() + 1)\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn m, nil\n\t\t}\n\n\tcase progress.Message:\n\t\treturn m, m.progress.SetPercent(float64(msg))\n\n\tcase progress_.FrameMsg:\n\t\treturn m, m.progress.Update(msg)\n\n\tcase zipMsg:\n\t\tm.state = installFont\n\t\tdefer func() {\n\t\t\tgo installFontZIP(msg, m)\n\t\t}()\n\t\tm.spinner.Spinner = spinner.Dot\n\t\treturn m, m.spinner.Tick\n\n\tcase successMsg:\n\t\tm.state = done\n\t\tm.families = msg\n\t\treturn m, tea.Quit\n\n\tcase errMsg:\n\t\tm.err = msg\n\t\treturn m, tea.Quit\n\n\tdefault:\n\t\ts, cmd := m.spinner.Update(msg)\n\t\tm.spinner = &s\n\t\treturn m, cmd\n\t}\n\n\tif m.list == nil {\n\t\treturn m, nil\n\t}\n\n\tlst, cmd := m.list.Update(msg)\n\tm.list = &lst\n\treturn m, cmd\n}\n\nfunc (m *main) View() string {\n\tif m.err != nil {\n\t\treturn textStyle.Render(m.err.Error())\n\t}\n\n\tswitch m.state {\n\tcase getFonts:\n\t\treturn textStyle.Render(fmt.Sprintf(\"%s Downloading font list%s\", m.spinner.View(), terminal.StartProgress()))\n\tcase selectFont:\n\t\treturn fmt.Sprintf(\"\\n%s%s\", m.list.View(), terminal.StopProgress())\n\tcase downloadFont:\n\t\treturn textStyle.Render(fmt.Sprintf(\"Downloading %s...\\n%s\", m.Name, m.progress.View()))\n\tcase unzipFont:\n\t\treturn textStyle.Render(fmt.Sprintf(\"%s Extracting %s\", m.spinner.View(), m.Name))\n\tcase installFont:\n\t\treturn textStyle.Render(fmt.Sprintf(\"%s Installing %s\", m.spinner.View(), m.Name))\n\tcase quit:\n\t\treturn textStyle.Render(fmt.Sprintf(\"No need to install a new font? That's cool.%s\", terminal.StopProgress()))\n\tcase done:\n\t\tif len(m.families) == 0 {\n\t\t\treturn textStyle.Render(fmt.Sprintf(\"No matching font families were installed. Try setting --zip-folder to the correct folder when using CascadiaCode (MS) or a custom font zip file. %s\", terminal.StopProgress())) //nolint: lll\n\t\t}\n\n\t\tsb := text.NewBuilder()\n\n\t\tsb.WriteString(fmt.Sprintf(\"Successfully installed %s 🚀\\n\\n%s\", m.Name, terminal.StopProgress()))\n\t\tsb.WriteString(\"The following font families are now available for configuration:\\n\\n\")\n\n\t\tfor i, family := range m.families {\n\t\t\tsb.WriteString(fmt.Sprintf(\"  • %s\", family))\n\n\t\t\tif i < len(m.families)-1 {\n\t\t\t\tsb.WriteString(\"\\n\")\n\t\t\t}\n\t\t}\n\n\t\treturn textStyle.Render(sb.String())\n\t}\n\n\treturn \"\"\n}\n\nfunc Run(font, zipFolder string, headless bool) (string, error) {\n\tif headless {\n\t\treturn installHeadless(font, zipFolder)\n\t}\n\n\treturn tui(font, zipFolder)\n}\n\nfunc tui(font, zipFolder string) (string, error) {\n\tmain := &main{\n\t\tAsset: Asset{\n\t\t\tName:   font,\n\t\t\tURL:    font,\n\t\t\tFolder: zipFolder,\n\t\t},\n\t}\n\n\tprogram = tea.NewProgram(main)\n\t_, err := program.Run()\n\treturn main.Name, err\n}\n\nfunc installHeadless(font, zipFolder string) (string, error) {\n\t// Handle local zip file\n\tif IsLocalZipFile(font) {\n\t\tdata, err := os.ReadFile(font)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\n\t\t_, err = InstallZIP(data, zipFolder)\n\t\treturn font, err\n\t}\n\n\treturn downloadAndInstall(font, zipFolder)\n}\n"
  },
  {
    "path": "src/cli/font.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/font\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tzipFolder string\n\theadless  bool\n\n\tfontCmd = &cobra.Command{\n\t\tUse:   \"font [install|configure]\",\n\t\tShort: \"Manage fonts\",\n\t\tLong: `Manage fonts.\n\nThis command is used to install fonts and configure the font in your terminal.\n\n  - install: oh-my-posh font install 3270`,\n\t\tValidArgs: []string{\n\t\t\t\"install\",\n\t\t\t\"configure\",\n\t\t},\n\t\tRun: func(cmd *cobra.Command, args []string) {\n\t\t\tif len(args) == 0 {\n\t\t\t\t_ = cmd.Help()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tswitch args[0] {\n\t\t\tcase \"install\":\n\t\t\t\tvar fontName string\n\t\t\t\tif len(args) > 1 {\n\t\t\t\t\tfontName = args[1]\n\t\t\t\t}\n\n\t\t\t\tenv := &runtime.Terminal{}\n\t\t\t\tenv.Init(&runtime.Flags{})\n\n\t\t\t\tsh := env.Shell()\n\n\t\t\t\tcache.Init(sh, cache.Persist)\n\n\t\t\t\tdefer func() {\n\t\t\t\t\tcache.Close()\n\t\t\t\t}()\n\n\t\t\t\tterminal.Init(sh)\n\n\t\t\t\tif !strings.HasPrefix(zipFolder, \"/\") {\n\t\t\t\t\tzipFolder += \"/\"\n\t\t\t\t}\n\n\t\t\t\tfontName, err := font.Run(fontName, zipFolder, headless)\n\t\t\t\tif err != nil {\n\t\t\t\t\tlog.Error(err)\n\t\t\t\t\texitcode = 70\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif env.Root() {\n\t\t\t\t\t// do not update the DSC cache if we are running as root\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tfontDSC := font.DSC()\n\t\t\t\tfontDSC.Load()\n\t\t\t\tfontDSC.Add(fontName)\n\t\t\t\tfontDSC.Save()\n\n\t\t\t\treturn\n\t\t\tcase \"configure\":\n\t\t\t\tfmt.Println(\"not implemented\")\n\t\t\tdefault:\n\t\t\t\t_ = cmd.Help()\n\t\t\t}\n\t\t},\n\t}\n)\n\nfunc init() {\n\tfontCmd.Flags().StringVar(&zipFolder, \"zip-folder\", \"\", \"the folder inside the zip file to install fonts from\")\n\tfontCmd.Flags().BoolVar(&headless, \"headless\", false, \"install font without TUI\")\n\tfontCmd.AddCommand(dsc.Command(font.DSC()))\n\tRootCmd.AddCommand(fontCmd)\n}\n"
  },
  {
    "path": "src/cli/get.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\n\tcolor2 \"github.com/gookit/color\"\n\t\"github.com/spf13/cobra\"\n)\n\n// getCmd represents the get command\nvar getCmd = &cobra.Command{\n\tUse:   \"get [shell|millis|accent|toggles|width]\",\n\tShort: \"Get a value from oh-my-posh\",\n\tLong: `Get a value from oh-my-posh.\n\nThis command is used to get the value of the following variables:\n\n- shell\n- millis\n- accent\n- toggles\n- width`,\n\tValidArgs: []string{\n\t\t\"millis\",\n\t\t\"shell\",\n\t\t\"accent\",\n\t\t\"toggles\",\n\t\t\"width\",\n\t\tcache.TTL,\n\t},\n\tArgs: NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tif args[0] == \"millis\" {\n\t\t\tfmt.Print(time.Now().UnixNano() / 1000000)\n\t\t\treturn\n\t\t}\n\n\t\tflags := &runtime.Flags{\n\t\t\tShell: os.Getenv(\"POSH_SHELL\"),\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(flags)\n\n\t\tswitch args[0] {\n\t\tcase \"shell\":\n\t\t\tfmt.Print(env.Shell())\n\t\t\treturn\n\t\tcase \"accent\":\n\t\t\trgb, err := color.GetAccentColor(env)\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"error getting accent color:\", err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t\taccent := color2.RGB(rgb.R, rgb.G, rgb.B)\n\t\t\tfmt.Print(\"#\" + accent.Hex())\n\t\t\treturn\n\t\tcase \"width\":\n\t\t\twidth, err := env.TerminalWidth()\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(\"error getting terminal width:\", err.Error())\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfmt.Print(width)\n\t\t\treturn\n\t\t}\n\n\t\tcache.Init(env.Shell(), cache.Persist)\n\n\t\tdefer func() {\n\t\t\tcache.Close()\n\t\t}()\n\n\t\tswitch args[0] {\n\t\tcase \"toggles\":\n\t\t\ttogglesMap, _ := cache.Get[map[string]bool](cache.Session, cache.TOGGLECACHE)\n\t\t\tif len(togglesMap) == 0 {\n\t\t\t\tfmt.Println(\"No segments are toggled off\")\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tfmt.Println(\"Toggled off segments:\")\n\t\t\tfor toggle := range togglesMap {\n\t\t\t\tfmt.Println(\"- \" + toggle)\n\t\t\t}\n\t\tcase cache.TTL:\n\t\t\tfmt.Print(cache.GetTTL())\n\t\tdefault:\n\t\t\t_ = cmd.Help()\n\t\t}\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(getCmd)\n}\n"
  },
  {
    "path": "src/cli/image/config.go",
    "content": "package image\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Settings represents the structure for base 16 color overrides and other image settings.\n// Expected JSON format:\n//\n//\t{\n//\t  \"colors\": {\n//\t    \"red\": \"#FF0000\",\n//\t    \"blue\": \"#0000FF\",\n//\t    \"green\": \"#00FF00\"\n//\t  },\n//\t  \"author\": \"Your Name\",\n//\t  \"background_color\": \"#FFFFFF\"\n//\t}\ntype Settings struct {\n\tColors          Colors `json:\"colors\"`\n\tAuthor          string `json:\"author\"`\n\tBackgroundColor string `json:\"background_color\"`\n\tFonts           *Fonts `json:\"fonts\"`\n\tCursor          string `json:\"cursor,omitempty\"`\n}\n\ntype Colors map[string]HexColor\n\nfunc NewColors() Colors {\n\treturn map[string]HexColor{}\n}\n\nfunc LoadSettings(filePath string) (*Settings, error) {\n\tif filePath == \"\" {\n\t\treturn nil, fmt.Errorf(\"color settings file path is empty\")\n\t}\n\n\tdata, err := os.ReadFile(filePath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read color settings file: %w\", err)\n\t}\n\n\tvar settings Settings\n\tif err := json.Unmarshal(data, &settings); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse color settings: %w\", err)\n\t}\n\n\treturn &settings, nil\n}\n\ntype HexColor string\n\nfunc (color HexColor) RGB() (*RGB, error) {\n\thex := string(color)\n\thex = strings.TrimPrefix(hex, \"#\")\n\n\tif len(hex) != 6 {\n\t\treturn nil, fmt.Errorf(\"invalid hex color format: %s\", hex)\n\t}\n\n\tvar r, g, b int64\n\tvar err error\n\n\tif r, err = strconv.ParseInt(hex[0:2], 16, 64); err != nil {\n\t\treturn nil, err\n\t}\n\tif g, err = strconv.ParseInt(hex[2:4], 16, 64); err != nil {\n\t\treturn nil, err\n\t}\n\tif b, err = strconv.ParseInt(hex[4:6], 16, 64); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &RGB{int(r), int(g), int(b)}, nil\n}\n\nfunc (colors Colors) RGBFromColorName(colorName string) (*RGB, error) {\n\tif colors == nil || colorName == \"\" {\n\t\treturn nil, fmt.Errorf(\"colors map or colorName is empty\")\n\t}\n\n\tif hexColor, exists := colors[colorName]; exists {\n\t\treturn hexColor.RGB()\n\t}\n\n\treturn nil, fmt.Errorf(\"color name '%s' not found in colors map\", colorName)\n}\n"
  },
  {
    "path": "src/cli/image/config_test.go",
    "content": "package image\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestLoadSettings(t *testing.T) {\n\tcases := []struct {\n\t\texpectedResult *Settings\n\t\tname           string\n\t\tjsonContent    string\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tname: \"Valid settings with all fields\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"colors\": {\n\t\t\t\t\t\"red\": \"#FF0000\",\n\t\t\t\t\t\"blue\": \"#0000FF\",\n\t\t\t\t\t\"green\": \"#00FF00\"\n\t\t\t\t},\n\t\t\t\t\"author\": \"John Doe\",\n\t\t\t\t\"background_color\": \"#FFFFFF\"\n\t\t\t}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors: map[string]HexColor{\n\t\t\t\t\t\"red\":   \"#FF0000\",\n\t\t\t\t\t\"blue\":  \"#0000FF\",\n\t\t\t\t\t\"green\": \"#00FF00\",\n\t\t\t\t},\n\t\t\t\tAuthor:          \"John Doe\",\n\t\t\t\tBackgroundColor: \"#FFFFFF\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Valid settings with only colors\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"colors\": {\n\t\t\t\t\t\"red\": \"#FF6B6B\",\n\t\t\t\t\t\"yellow\": \"#FFA07A\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors: map[string]HexColor{\n\t\t\t\t\t\"red\":    \"#FF6B6B\",\n\t\t\t\t\t\"yellow\": \"#FFA07A\",\n\t\t\t\t},\n\t\t\t\tAuthor:          \"\",\n\t\t\t\tBackgroundColor: \"\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Valid settings with only author\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"author\": \"Jane Smith\"\n\t\t\t}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors:          nil,\n\t\t\t\tAuthor:          \"Jane Smith\",\n\t\t\t\tBackgroundColor: \"\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname:        \"Empty JSON object\",\n\t\t\tjsonContent: `{}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors:          nil,\n\t\t\t\tAuthor:          \"\",\n\t\t\t\tBackgroundColor: \"\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"Invalid JSON\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"colors\": {\n\t\t\t\t\t\"red\": \"#FF0000\"\n\t\t\t\t\"author\": \"John Doe\"\n\t\t\t}`,\n\t\t\texpectedResult: nil,\n\t\t\texpectError:    true,\n\t\t},\n\t\t{\n\t\t\tname: \"JSON with invalid color format\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"colors\": {\n\t\t\t\t\t\"red\": \"not-a-color\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors: map[string]HexColor{\n\t\t\t\t\t\"red\": \"not-a-color\",\n\t\t\t\t},\n\t\t\t\tAuthor:          \"\",\n\t\t\t\tBackgroundColor: \"\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"JSON with extended color names\",\n\t\t\tjsonContent: `{\n\t\t\t\t\"colors\": {\n\t\t\t\t\t\"lightRed\": \"#FF9999\",\n\t\t\t\t\t\"darkGray\": \"#333333\",\n\t\t\t\t\t\"lightBlue\": \"#87CEEB\"\n\t\t\t\t}\n\t\t\t}`,\n\t\t\texpectedResult: &Settings{\n\t\t\t\tColors: map[string]HexColor{\n\t\t\t\t\t\"lightRed\":  \"#FF9999\",\n\t\t\t\t\t\"darkGray\":  \"#333333\",\n\t\t\t\t\t\"lightBlue\": \"#87CEEB\",\n\t\t\t\t},\n\t\t\t\tAuthor:          \"\",\n\t\t\t\tBackgroundColor: \"\",\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\t// Create a temporary file\n\t\t\ttempFile := createTempFile(t, tc.jsonContent)\n\t\t\tdefer os.Remove(tempFile)\n\n\t\t\t// Test LoadSettings\n\t\t\tresult, err := LoadSettings(tempFile)\n\n\t\t\tif tc.expectError {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expectedResult, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// Helper interface for testing types that have TempDir method\ntype testingInterface interface {\n\tTempDir() string\n\tHelper()\n}\n\n// Helper function to create a temporary file with given content\nfunc createTempFile(t testingInterface, content string) string {\n\tt.Helper()\n\ttempDir := t.TempDir()\n\ttempFile := filepath.Join(tempDir, \"test-settings.json\")\n\n\terr := os.WriteFile(tempFile, []byte(content), 0644)\n\tif err != nil {\n\t\tpanic(err) // Use panic since we can't return error from generic interface\n\t}\n\n\treturn tempFile\n}\n"
  },
  {
    "path": "src/cli/image/fonts.go",
    "content": "package image\n\nimport (\n\t\"fmt\"\n\tstdOS \"os\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\n\t\"golang.org/x/image/font\"\n\t\"golang.org/x/image/font/opentype\"\n)\n\nconst (\n\tregular = \"regular\"\n)\n\ntype Fonts struct {\n\tRegular string `json:\"regular\"`\n\tBold    string `json:\"bold\"`\n\tItalic  string `json:\"italic\"`\n}\n\nfunc (f *Fonts) IsValid() bool {\n\tif f == nil {\n\t\treturn false\n\t}\n\n\t// Check that all required font paths are non-empty\n\treturn f.Regular != \"\" && f.Bold != \"\" && f.Italic != \"\"\n}\n\nfunc (f *Fonts) Load() (map[string]font.Face, error) {\n\tdefer log.Trace(time.Now())\n\n\tresult := make(map[string]font.Face)\n\n\tfonts := map[string]Font{\n\t\tregular: Font(f.Regular),\n\t\tbold:    Font(f.Bold),\n\t\titalic:  Font(f.Italic),\n\t}\n\n\tfor name, fontPath := range fonts {\n\t\tfontFace, err := fontPath.Load()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to load font %s: %w\", fontPath, err)\n\t\t}\n\n\t\tresult[name] = fontFace\n\t}\n\n\treturn result, nil\n}\n\ntype Font string\n\nfunc (f Font) Load() (font.Face, error) {\n\tdefer log.Trace(time.Now(), string(f))\n\n\tdata, err := stdOS.ReadFile(string(f))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read font file %s: %w\", f, err)\n\t}\n\n\tfontObject, err := opentype.Parse(data)\n\n\t// handle collections\n\tif err != nil {\n\t\tcollection, err := opentype.ParseCollection(data)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse font %s as single font or collection: %w\", f, err)\n\t\t}\n\n\t\tif collection.NumFonts() == 0 {\n\t\t\treturn nil, fmt.Errorf(\"font collection %s is empty\", f)\n\t\t}\n\n\t\tfontObject, err = collection.Font(0)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get first font from collection %s: %w\", f, err)\n\t\t}\n\t}\n\n\tface, err := opentype.NewFace(fontObject, &opentype.FaceOptions{Size: 2.0 * 12, DPI: 144})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create font face for %s: %w\", f, err)\n\t}\n\n\tif face == nil {\n\t\treturn nil, fmt.Errorf(\"failed to create font face for %s: face is nil\", f)\n\t}\n\n\treturn face, nil\n}\n"
  },
  {
    "path": "src/cli/image/image.go",
    "content": "// Copyright © 2020 The Homeport Team\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the \"Software\"), to deal\n// in the Software without restriction, including without limitation the rights\n// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n// copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n// THE SOFTWARE.\n\n// https://github.com/homeport/termshot\n\npackage image\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"image\"\n\t\"io\"\n\t\"math\"\n\tstdOS \"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\tfont_ \"github.com/jandedobbeleer/oh-my-posh/src/cli/font\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\n\t\"github.com/esimov/stackblur-go\"\n\t\"github.com/fogleman/gg\"\n\t\"golang.org/x/image/font\"\n\t\"golang.org/x/image/font/opentype\"\n)\n\ntype ConnectionError struct {\n\treason string\n}\n\nfunc (f *ConnectionError) Error() string {\n\treturn f.reason\n}\n\nconst (\n\tred    = \"#ED655A\"\n\tyellow = \"#E1C04C\"\n\tgreen  = \"#71BD47\"\n\n\t// known ansi sequences\n\n\tfg                  = \"FG\"\n\tbg                  = \"BG\"\n\tbc                  = \"BC\" // for base 16 colors\n\tstr                 = \"STR\"\n\ttext                = \"TEXT\"\n\tinvertedColor       = \"inverted\"\n\tinvertedColorSingle = \"invertedsingle\"\n\tfullColor           = \"full\"\n\tforeground          = \"foreground\"\n\tbackground          = \"background\"\n\treset               = \"reset\"\n\tbold                = \"bold\"\n\tboldReset           = \"boldr\"\n\titalic              = \"italic\"\n\titalicReset         = \"italicr\"\n\tunderline           = \"underline\"\n\tunderlineReset      = \"underliner\"\n\toverline            = \"overline\"\n\toverlineReset       = \"overliner\"\n\tstrikethrough       = \"strikethrough\"\n\tstrikethroughReset  = \"strikethroughr\"\n\tbackgroundReset     = \"backgroundr\"\n\tcolor16             = \"color16\"\n\tleft                = \"left\"\n\tlineChange          = \"linechange\"\n\tconsoleTitle        = \"title\"\n\tlink                = \"link\"\n)\n\ntype RGB struct {\n\tr int\n\tg int\n\tb int\n}\n\nfunc NewRGBColor(ansiColor string) *RGB {\n\tcolors := strings.Split(ansiColor, \";\")\n\tb, _ := strconv.Atoi(colors[2])\n\tg, _ := strconv.Atoi(colors[1])\n\tr, _ := strconv.Atoi(colors[0])\n\treturn &RGB{\n\t\tr: r,\n\t\tg: g,\n\t\tb: b,\n\t}\n}\n\ntype Renderer struct {\n\titalic                 font.Face\n\tbold                   font.Face\n\tregular                font.Face\n\tbackgroundColor        *RGB\n\tansiSequenceRegexMap   map[string]string\n\tforegroundColor        *RGB\n\tdefaultBackgroundColor *RGB\n\tdefaultForegroundColor *RGB\n\tSettings\n\tPath            string\n\tAnsiString      string\n\tshadowBaseColor string\n\tstyle           string\n\tshadowOffsetX   float64\n\tmargin          float64\n\tfactor          float64\n\tshadowOffsetY   float64\n\trows            int\n\tlineSpacing     float64\n\tcolumns         int\n\tpadding         float64\n\tshadowRadius    uint8\n}\n\nfunc (ir *Renderer) Init(env runtime.Environment) error {\n\tir.setOutputPath(env.Flags().ConfigPath)\n\n\tir.cleanContent()\n\n\tif err := ir.loadFonts(); err != nil {\n\t\treturn err\n\t}\n\n\tir.initDefaults()\n\n\treturn nil\n}\n\nfunc (ir *Renderer) loadFonts() error {\n\tif !ir.Fonts.IsValid() {\n\t\treturn ir.loadDefaultFonts()\n\t}\n\n\tfonts, err := ir.Fonts.Load()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tir.regular = fonts[regular]\n\tir.bold = fonts[bold]\n\tir.italic = fonts[italic]\n\n\treturn nil\n}\n\nfunc (ir *Renderer) initDefaults() {\n\tir.defaultForegroundColor = &RGB{255, 255, 255}\n\tir.defaultBackgroundColor = &RGB{21, 21, 21}\n\n\tir.factor = 2.0\n\tir.columns = 80\n\tir.rows = 25\n\n\tir.margin = ir.factor * 48\n\tir.padding = ir.factor * 24\n\n\tir.shadowBaseColor = \"#10101066\"\n\tir.shadowRadius = uint8(math.Min(ir.factor*16, 255))\n\tir.shadowOffsetX = ir.factor * 16\n\tir.shadowOffsetY = ir.factor * 16\n\n\tir.lineSpacing = 1.2\n\n\t// Set background color from settings if provided, otherwise use default\n\tif ir.BackgroundColor == \"\" {\n\t\tir.BackgroundColor = \"#151515\" // Default dark background\n\t}\n\n\tir.ansiSequenceRegexMap = map[string]string{\n\t\tinvertedColor:       `^(?P<STR>(\\x1b\\[38;2;(?P<BG>(\\d+;?){3});49m){1}(\\x1b\\[7m))`,\n\t\tinvertedColorSingle: `^(?P<STR>\\x1b\\[(?P<BG>\\d{2,3});49m\\x1b\\[7m)`,\n\t\tfullColor:           `^(?P<STR>(\\x1b\\[48;2;(?P<BG>(\\d+;?){3})m)(\\x1b\\[38;2;(?P<FG>(\\d+;?){3})m))`,\n\t\tforeground:          `^(?P<STR>(\\x1b\\[38;2;(?P<FG>(\\d+;?){3})m))`,\n\t\tbackground:          `^(?P<STR>(\\x1b\\[48;2;(?P<BG>(\\d+;?){3})m))`,\n\t\treset:               `^(?P<STR>\\x1b\\[0m)`,\n\t\tbold:                `^(?P<STR>\\x1b\\[1m)`,\n\t\tboldReset:           `^(?P<STR>\\x1b\\[22m)`,\n\t\titalic:              `^(?P<STR>\\x1b\\[3m)`,\n\t\titalicReset:         `^(?P<STR>\\x1b\\[23m)`,\n\t\tunderline:           `^(?P<STR>\\x1b\\[4m)`,\n\t\tunderlineReset:      `^(?P<STR>\\x1b\\[24m)`,\n\t\toverline:            `^(?P<STR>\\x1b\\[53m)`,\n\t\toverlineReset:       `^(?P<STR>\\x1b\\[55m)`,\n\t\tstrikethrough:       `^(?P<STR>\\x1b\\[9m)`,\n\t\tstrikethroughReset:  `^(?P<STR>\\x1b\\[29m)`,\n\t\tbackgroundReset:     `^(?P<STR>\\x1b\\[49m)`,\n\t\tcolor16:             `^(?P<STR>\\x1b\\[(?P<BC>[349][0-7]|10[0-7]|39)m)`,\n\t\tleft:                `^(?P<STR>\\x1b\\[(\\d{1,3})D)`,\n\t\tlineChange:          `^(?P<STR>\\x1b\\[(\\d)[FB])`,\n\t\tconsoleTitle:        `^(?P<STR>\\x1b\\]0;(.+)\\007)`,\n\t\tlink:                fmt.Sprintf(`^%s`, regex.LINK),\n\t}\n}\n\nfunc (ir *Renderer) setOutputPath(config string) {\n\tif len(ir.Path) != 0 {\n\t\treturn\n\t}\n\n\tif config == \"\" {\n\t\tir.Path = \"prompt.png\"\n\t\treturn\n\t}\n\n\tconfig = filepath.Base(config)\n\n\tmatch := regex.FindNamedRegexMatch(`(\\.?)(?P<STR>.*)\\.(json|yaml|yml|toml|jsonc)`, config)\n\tpath := strings.TrimRight(match[str], \".omp\")\n\n\tif path == \"\" {\n\t\tpath = \"prompt\"\n\t}\n\n\tir.Path = fmt.Sprintf(\"%s.png\", path)\n}\n\nfunc (ir *Renderer) loadDefaultFonts() error {\n\tvar data []byte\n\n\tfontCachePath := filepath.Join(cache.Path(), \"Hack.zip\")\n\tif _, err := stdOS.Stat(fontCachePath); err == nil {\n\t\tdata, _ = stdOS.ReadFile(fontCachePath)\n\t}\n\n\t// Download font if not cached\n\tif data == nil {\n\t\turl := \"https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/Hack.zip\"\n\t\tvar err error\n\n\t\tdata, err = font_.Download(url)\n\t\tif err != nil {\n\t\t\treturn &ConnectionError{reason: err.Error()}\n\t\t}\n\n\t\terr = stdOS.WriteFile(fontCachePath, data, 0644)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tbytesReader := bytes.NewReader(data)\n\tzipReader, err := zip.NewReader(bytesReader, int64(bytesReader.Len()))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfontFaceOptions := &opentype.FaceOptions{Size: 2.0 * 12, DPI: 144}\n\n\tparseFont := func(file *zip.File) (font.Face, error) {\n\t\trc, err := file.Open()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tdefer rc.Close()\n\n\t\tdata, err := io.ReadAll(rc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfont, err := opentype.Parse(data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tfontFace, err := opentype.NewFace(font, fontFaceOptions)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn fontFace, nil\n\t}\n\n\tfor _, file := range zipReader.File {\n\t\tswitch file.Name {\n\t\tcase \"HackNerdFont-Regular.ttf\":\n\t\t\tif regular, err := parseFont(file); err == nil {\n\t\t\t\tir.regular = regular\n\t\t\t}\n\t\tcase \"HackNerdFont-Bold.ttf\":\n\t\t\tif bold, err := parseFont(file); err == nil {\n\t\t\t\tir.bold = bold\n\t\t\t}\n\t\tcase \"HackNerdFont-Italic.ttf\":\n\t\t\tif italic, err := parseFont(file); err == nil {\n\t\t\t\tir.italic = italic\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (ir *Renderer) fontHeight() float64 {\n\treturn float64(ir.regular.Metrics().Height >> 6)\n}\n\ntype RuneRange struct {\n\tStart rune\n\tEnd   rune\n}\n\n// If we're a Nerd Font code point, treat as double width\nvar doubleWidthRunes = []RuneRange{\n\t// Seti-UI + Custom range\n\t{Start: '\\ue5fa', End: '\\ue6b1'},\n\t// Devicons\n\t{Start: '\\ue700', End: '\\ue7c5'},\n\t// Font Awesome\n\t{Start: '\\uf000', End: '\\uf2e0'},\n\t// Font Awesome Extension\n\t{Start: '\\ue200', End: '\\ue2a9'},\n\t// Material Design Icons\n\t{Start: '\\U000f0001', End: '\\U000f1af0'},\n\t// Weather\n\t{Start: '\\ue300', End: '\\ue3e3'},\n\t// Octicons\n\t{Start: '\\uf400', End: '\\uf532'},\n\t{Start: '\\u2665', End: '\\u2665'},\n\t{Start: '\\u26A1', End: '\\u26A1'},\n\t// Powerline Extra Symbols (intentionally excluding single width bubbles (e0b4-e0b7) and pixelated (e0c4-e0c7))\n\t{Start: '\\ue0a3', End: '\\ue0a3'},\n\t{Start: '\\ue0b4', End: '\\ue0c8'},\n\t{Start: '\\ue0ca', End: '\\ue0ca'},\n\t{Start: '\\ue0cc', End: '\\ue0d4'},\n\t// IEC Power Symbols\n\t{Start: '\\u23fb', End: '\\u23fe'},\n\t{Start: '\\u2b58', End: '\\u2b58'},\n\t// Font Logos\n\t{Start: '\\uf300', End: '\\uf372'},\n\t// Pomicons\n\t{Start: '\\ue000', End: '\\ue00a'},\n\t// Codicons\n\t{Start: '\\uea60', End: '\\uebeb'},\n}\n\n// This is getting how many additional characters of width to allocate when drawing\n// e.g. for characters that are 2 or more wide. A standard character will return 0\n// Nerd Font glyphs will return 1, since most are double width\nfunc (ir *Renderer) runeAdditionalWidth(r rune) int {\n\t// exclude the round leading diamond\n\tsingles := []rune{'\\ue0b6', '\\ue0ba', '\\ue0bc'}\n\tif slices.Contains(singles, r) {\n\t\treturn 0\n\t}\n\n\tfor _, runeRange := range doubleWidthRunes {\n\t\tif runeRange.Start <= r && r <= runeRange.End {\n\t\t\treturn 1\n\t\t}\n\t}\n\treturn 0\n}\n\nfunc (ir *Renderer) cleanContent() {\n\t// clean abundance of empty lines\n\tir.AnsiString = strings.Trim(ir.AnsiString, \"\\n\")\n\tir.AnsiString = \"\\n\" + ir.AnsiString\n\n\t// clean string before render\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\x1b[m\", \"\\x1b[0m\")\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\x1b[K\", \"\")\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\x1b[0J\", \"\")\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\x1b[27m\", \"\")\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\x1b8\", \"\")\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, \"\\u2800\", \" \")\n\n\t// cursor indication\n\tsaveCursorAnsi := \"\\x1b7\"\n\tif !strings.Contains(ir.AnsiString, saveCursorAnsi) {\n\t\tir.AnsiString += ir.Cursor\n\t}\n\n\tir.AnsiString = strings.ReplaceAll(ir.AnsiString, saveCursorAnsi, ir.Cursor)\n\n\t// add watermarks\n\tir.AnsiString += \"\\n\\n\\x1b[1mohmyposh.dev\\x1b[22m\"\n\tif len(ir.Author) > 0 {\n\t\tcreatedBy := fmt.Sprintf(\" by \\x1b[1m%s\\x1b[22m\", ir.Author)\n\t\tir.AnsiString += createdBy\n\t}\n}\n\nfunc (ir *Renderer) measureContent() (width, height float64) {\n\t// Use actual rendering logic for accurate width measurement\n\t// This simulates the exact same process as the actual drawing to ensure\n\t// the canvas width perfectly matches the rendered content width\n\tvar maxX float64\n\tvar x float64\n\n\t// Save original ansi string and style state\n\toriginalAnsi := ir.AnsiString\n\toriginalStyle := ir.style\n\tir.style = \"\"\n\n\ttmpDrawer := &font.Drawer{Face: ir.regular}\n\n\tfor ir.AnsiString != \"\" {\n\t\tif !ir.processAnsiSequence() {\n\t\t\tcontinue\n\t\t}\n\n\t\trunes := []rune(ir.AnsiString)\n\t\tif len(runes) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tstr := string(runes[0:1])\n\t\tir.AnsiString = string(runes[1:])\n\n\t\t// Use appropriate font face for measurement\n\t\tvar face font.Face\n\t\tswitch ir.style {\n\t\tcase bold:\n\t\t\tface = ir.bold\n\t\tcase italic:\n\t\t\tface = ir.italic\n\t\tdefault:\n\t\t\tface = ir.regular\n\t\t}\n\n\t\ttmpDrawer.Face = face\n\t\tadvance := tmpDrawer.MeasureString(str)\n\t\tw := float64(advance >> 6)\n\n\t\t// Add additional width for Nerd Font glyphs\n\t\tw += (w * float64(ir.runeAdditionalWidth(runes[0])))\n\n\t\tif str == \"\\n\" {\n\t\t\tx = 0\n\t\t\tcontinue\n\t\t}\n\n\t\tx += w\n\t\tif x > maxX {\n\t\t\tmaxX = x\n\t\t}\n\t}\n\n\t// Restore original state\n\tir.AnsiString = originalAnsi\n\tir.style = originalStyle\n\n\t// Ensure we have a minimum width for very short content\n\tminWidth := tmpDrawer.MeasureString(strings.Repeat(\" \", 80))\n\twidth = math.Max(maxX, float64(minWidth>>6))\n\n\t// height, lines times font height and line spacing\n\tlines := strings.Split(originalAnsi, \"\\n\")\n\theight = float64(len(lines)) * ir.fontHeight() * ir.lineSpacing\n\treturn width, height\n}\n\nfunc (ir *Renderer) SavePNG() error {\n\tvar scale = func(value float64) float64 { return ir.factor * value }\n\n\tvar (\n\t\tcorner   = scale(6)\n\t\tradius   = scale(9)\n\t\tdistance = scale(25)\n\t)\n\n\tcontentWidth, contentHeight := ir.measureContent()\n\n\t// Make sure the output window is big enough in case no content or very few\n\t// content will be rendered. Also account for potential font variations.\n\tminRequiredWidth := 3*distance + 3*radius\n\t// Add extra buffer for wider fonts (20% more than minimum)\n\tminRequiredWidth *= 1.2\n\tcontentWidth = math.Max(contentWidth, minRequiredWidth)\n\n\tmarginX, marginY := ir.margin, ir.margin\n\tpaddingX, paddingY := ir.padding, ir.padding\n\n\txOffset := marginX\n\tyOffset := marginY\n\ttitleOffset := scale(40)\n\n\twidth := contentWidth + 2*marginX + 2*paddingX\n\theight := contentHeight + 2*marginY + 2*paddingY + titleOffset\n\n\tdc := gg.NewContext(int(width), int(height))\n\n\txOffset -= ir.shadowOffsetX / 2\n\tyOffset -= ir.shadowOffsetY / 2\n\n\tbc := gg.NewContext(int(width), int(height))\n\tbc.DrawRoundedRectangle(xOffset+ir.shadowOffsetX, yOffset+ir.shadowOffsetY, width-2*marginX, height-2*marginY, corner)\n\tbc.SetHexColor(ir.shadowBaseColor)\n\tbc.Fill()\n\n\tdst := image.NewNRGBA(bc.Image().Bounds())\n\n\t// var done = make(chan struct{}, ir.shadowRadius)\n\terr := stackblur.Process(\n\t\tdst,\n\t\tbc.Image(),\n\t\tuint32(ir.shadowRadius),\n\t)\n\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// <-done\n\tdc.DrawImage(dst, 0, 0)\n\n\t// Draw rounded rectangle with outline and three button to produce the\n\t// impression of a window with controls and a content area\n\tdc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)\n\tdc.SetHexColor(ir.BackgroundColor)\n\tdc.Fill()\n\n\tdc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)\n\tdc.SetHexColor(\"#404040\")\n\tdc.SetLineWidth(scale(1))\n\tdc.Stroke()\n\n\tfor i, color := range []string{red, yellow, green} {\n\t\tdc.DrawCircle(xOffset+paddingX+float64(i)*distance+scale(4), yOffset+paddingY+scale(4), radius)\n\t\tdc.SetHexColor(color)\n\t\tdc.Fill()\n\t}\n\n\t// Apply the actual text into the prepared content area of the window\n\tvar x, y = xOffset + paddingX, yOffset + paddingY + titleOffset + ir.fontHeight()\n\n\tfor ir.AnsiString != \"\" {\n\t\tif !ir.processAnsiSequence() {\n\t\t\tcontinue\n\t\t}\n\n\t\trunes := []rune(ir.AnsiString)\n\t\tif len(runes) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tstr := string(runes[0:1])\n\t\tir.AnsiString = string(runes[1:])\n\t\tswitch ir.style {\n\t\tcase bold:\n\t\t\tdc.SetFontFace(ir.bold)\n\t\tcase italic:\n\t\t\tdc.SetFontFace(ir.italic)\n\t\tdefault:\n\t\t\tdc.SetFontFace(ir.regular)\n\t\t}\n\n\t\tw, _ := dc.MeasureString(str)\n\t\t// The gg library unfortunately returns a single character width for *all* glyphs in a font.\n\t\t// So if we know the glyph to occupy n additional characters in width, allocate that area\n\t\t// e.g. this will double the space for Nerd Fonts, but some could even be 3 or 4 wide\n\t\t// If there's 0 additional characters of width (the common case), this won't add anything\n\t\tw += (w * float64(ir.runeAdditionalWidth(runes[0])))\n\n\t\tif ir.backgroundColor != nil {\n\t\t\tdc.SetRGB255(ir.backgroundColor.r, ir.backgroundColor.g, ir.backgroundColor.b)\n\t\t\t// Use consistent line height for all background rectangles\n\t\t\tfontLineHeight := ir.fontHeight() * ir.lineSpacing\n\n\t\t\t// Center all characters (including powerline glyphs) within the line height\n\t\t\t// Position background to align properly with text baseline and ensure consistent height\n\t\t\tbgY := y - fontLineHeight*0.75 // Adjusted for better centering with text\n\t\t\tbgHeight := fontLineHeight\n\n\t\t\tdc.DrawRectangle(x, bgY, w, bgHeight)\n\t\t\tdc.Fill()\n\t\t}\n\n\t\tif ir.foregroundColor != nil {\n\t\t\tdc.SetRGB255(ir.foregroundColor.r, ir.foregroundColor.g, ir.foregroundColor.b)\n\t\t} else {\n\t\t\tdc.SetRGB255(ir.defaultForegroundColor.r, ir.defaultForegroundColor.g, ir.defaultForegroundColor.b)\n\t\t}\n\n\t\tif str == \"\\n\" {\n\t\t\tx = xOffset + paddingX\n\t\t\ty += ir.fontHeight() * ir.lineSpacing // Use consistent line height instead of character height\n\t\t\tcontinue\n\t\t}\n\n\t\tdc.DrawString(str, x, y)\n\n\t\tif ir.style == underline {\n\t\t\tdc.DrawLine(x, y+scale(4), x+w, y+scale(4))\n\t\t\tdc.SetLineWidth(scale(1))\n\t\t\tdc.Stroke()\n\t\t}\n\n\t\tif ir.style == overline {\n\t\t\tdc.DrawLine(x, y-scale(22), x+w, y-scale(22))\n\t\t\tdc.SetLineWidth(scale(1))\n\t\t\tdc.Stroke()\n\t\t}\n\n\t\tx += w\n\t}\n\n\treturn dc.SavePNG(ir.Path)\n}\n\nfunc (ir *Renderer) processAnsiSequence() bool {\n\tfor sequence, re := range ir.ansiSequenceRegexMap {\n\t\tmatch := regex.FindNamedRegexMatch(re, ir.AnsiString)\n\t\tif len(match) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tir.AnsiString = strings.TrimPrefix(ir.AnsiString, match[str])\n\t\tswitch sequence {\n\t\tcase invertedColor:\n\t\t\tir.foregroundColor = ir.defaultBackgroundColor\n\t\t\tir.backgroundColor = NewRGBColor(match[bg])\n\t\t\treturn false\n\t\tcase invertedColorSingle:\n\t\t\tir.foregroundColor = ir.defaultBackgroundColor\n\t\t\tbgColor, _ := strconv.Atoi(match[bg])\n\t\t\tbgColor += 10\n\t\t\tir.setBase16Color(fmt.Sprint(bgColor))\n\t\t\treturn false\n\t\tcase fullColor:\n\t\t\tir.foregroundColor = NewRGBColor(match[fg])\n\t\t\tir.backgroundColor = NewRGBColor(match[bg])\n\t\t\treturn false\n\t\tcase foreground:\n\t\t\tir.foregroundColor = NewRGBColor(match[fg])\n\t\t\treturn false\n\t\tcase background:\n\t\t\tir.backgroundColor = NewRGBColor(match[bg])\n\t\t\treturn false\n\t\tcase reset:\n\t\t\tir.foregroundColor = ir.defaultForegroundColor\n\t\t\tir.backgroundColor = nil\n\t\t\treturn false\n\t\tcase backgroundReset:\n\t\t\tir.backgroundColor = nil\n\t\t\treturn false\n\t\tcase bold, italic, underline, overline:\n\t\t\tir.style = sequence\n\t\t\treturn false\n\t\tcase boldReset, italicReset, underlineReset, overlineReset:\n\t\t\tir.style = \"\"\n\t\t\treturn false\n\t\tcase strikethrough, strikethroughReset, left, lineChange, consoleTitle:\n\t\t\treturn false\n\t\tcase color16:\n\t\t\tir.setBase16Color(match[bc])\n\t\t\treturn false\n\t\tcase link:\n\t\t\tir.AnsiString = match[text] + ir.AnsiString\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (ir *Renderer) setBase16Color(colorStr string) {\n\ttempColor := ir.defaultForegroundColor\n\n\tcolorInt, err := strconv.Atoi(colorStr)\n\tif err != nil {\n\t\tir.foregroundColor = tempColor\n\t\treturn\n\t}\n\n\t// Check for color override first\n\tcolorName := colorNameFromCode(colorInt)\n\tif rgb, err := ir.Colors.RGBFromColorName(colorName); err == nil {\n\t\ttempColor = rgb\n\t}\n\n\t// If no override found, use default colors\n\tif tempColor == ir.defaultForegroundColor {\n\t\tswitch colorInt {\n\t\tcase 30, 40: // Black\n\t\t\ttempColor = &RGB{1, 1, 1}\n\t\tcase 31, 41: // Red\n\t\t\ttempColor = &RGB{222, 56, 43}\n\t\tcase 32, 42: // Green\n\t\t\ttempColor = &RGB{57, 181, 74}\n\t\tcase 33, 43: // Yellow\n\t\t\ttempColor = &RGB{255, 199, 6}\n\t\tcase 34, 44: // Blue\n\t\t\ttempColor = &RGB{0, 111, 184}\n\t\tcase 35, 45: // Magenta\n\t\t\ttempColor = &RGB{118, 38, 113}\n\t\tcase 36, 46: // Cyan\n\t\t\ttempColor = &RGB{44, 181, 233}\n\t\tcase 37, 47: // White\n\t\t\ttempColor = &RGB{204, 204, 204}\n\t\tcase 90, 100: // Bright Black (Gray)\n\t\t\ttempColor = &RGB{128, 128, 128}\n\t\tcase 91, 101: // Bright Red\n\t\t\ttempColor = &RGB{255, 0, 0}\n\t\tcase 92, 102: // Bright Green\n\t\t\ttempColor = &RGB{0, 255, 0}\n\t\tcase 93, 103: // Bright Yellow\n\t\t\ttempColor = &RGB{255, 255, 0}\n\t\tcase 94, 104: // Bright Blue\n\t\t\ttempColor = &RGB{0, 0, 255}\n\t\tcase 95, 105: // Bright Magenta\n\t\t\ttempColor = &RGB{255, 0, 255}\n\t\tcase 96, 106: // Bright Cyan\n\t\t\ttempColor = &RGB{101, 194, 205}\n\t\tcase 97, 107: // Bright White\n\t\t\ttempColor = &RGB{255, 255, 255}\n\t\t}\n\t}\n\n\tif colorInt < 40 || (colorInt >= 90 && colorInt < 100) {\n\t\tir.foregroundColor = tempColor\n\t\treturn\n\t}\n\n\tir.backgroundColor = tempColor\n}\n\n// colorNameFromCode maps ANSI color codes to color names\nfunc colorNameFromCode(colorInt int) string {\n\tswitch colorInt {\n\tcase 30, 40:\n\t\treturn \"black\"\n\tcase 31, 41:\n\t\treturn \"red\"\n\tcase 32, 42:\n\t\treturn \"green\"\n\tcase 33, 43:\n\t\treturn \"yellow\"\n\tcase 34, 44:\n\t\treturn \"blue\"\n\tcase 35, 45:\n\t\treturn \"magenta\"\n\tcase 36, 46:\n\t\treturn \"cyan\"\n\tcase 37, 47:\n\t\treturn \"white\"\n\tcase 90, 100:\n\t\treturn \"darkGray\"\n\tcase 91, 101:\n\t\treturn \"lightRed\"\n\tcase 92, 102:\n\t\treturn \"lightGreen\"\n\tcase 93, 103:\n\t\treturn \"lightYellow\"\n\tcase 94, 104:\n\t\treturn \"lightBlue\"\n\tcase 95, 105:\n\t\treturn \"lightMagenta\"\n\tcase 96, 106:\n\t\treturn \"lightCyan\"\n\tcase 97, 107:\n\t\treturn \"lightWhite\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "src/cli/image/image_test.go",
    "content": "package image\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSetOutputPath(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tConfig   string\n\t\tPath     string\n\t\tExpected string\n\t}{\n\t\t{Case: \"default config\", Expected: \"prompt.png\"},\n\t\t{Case: \"hidden file\", Config: \".posh.omp.json\", Expected: \"posh.png\"},\n\t\t{Case: \"hidden file toml\", Config: \".posh.omp.toml\", Expected: \"posh.png\"},\n\t\t{Case: \"hidden file yaml\", Config: \".posh.omp.yaml\", Expected: \"posh.png\"},\n\t\t{Case: \"hidden file yml\", Config: \".posh.omp.yml\", Expected: \"posh.png\"},\n\t\t{Case: \"path provided\", Path: \"mytheme.png\", Expected: \"mytheme.png\"},\n\t\t{Case: \"relative, no omp\", Config: \"~/jandedobbeleer.json\", Expected: \"jandedobbeleer.png\"},\n\t\t{Case: \"relative path\", Config: \"~/jandedobbeleer.omp.json\", Expected: \"jandedobbeleer.png\"},\n\t\t{Case: \"invalid config name\", Config: \"~/jandedobbeleer.omp.foo\", Expected: \"prompt.png\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\timage := &Renderer{\n\t\t\tPath: tc.Path,\n\t\t}\n\n\t\timage.setOutputPath(tc.Config)\n\n\t\tassert.Equal(t, tc.Expected, image.Path, tc.Case)\n\t}\n}\n\nfunc TestHexToRGB(t *testing.T) {\n\tcases := []struct {\n\t\texpected *RGB\n\t\tname     string\n\t\thex      HexColor\n\t\thasError bool\n\t}{\n\t\t{\n\t\t\tname:     \"Valid hex with hash\",\n\t\t\thex:      \"#FF0000\",\n\t\t\texpected: &RGB{255, 0, 0},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname:     \"Valid hex without hash\",\n\t\t\thex:      \"00FF00\",\n\t\t\texpected: &RGB{0, 255, 0},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname:     \"Valid hex blue\",\n\t\t\thex:      \"#0000FF\",\n\t\t\texpected: &RGB{0, 0, 255},\n\t\t\thasError: false,\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid hex too short\",\n\t\t\thex:      \"#FFF\",\n\t\t\texpected: nil,\n\t\t\thasError: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid hex too long\",\n\t\t\thex:      \"#FFFFFFF\",\n\t\t\texpected: nil,\n\t\t\thasError: true,\n\t\t},\n\t\t{\n\t\t\tname:     \"Invalid hex characters\",\n\t\t\thex:      \"#GGGGGG\",\n\t\t\texpected: nil,\n\t\t\thasError: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tresult, err := tc.hex.RGB()\n\n\t\t\tif tc.hasError {\n\t\t\t\tassert.Error(t, err)\n\t\t\t\tassert.Nil(t, result)\n\t\t\t} else {\n\t\t\t\tassert.NoError(t, err)\n\t\t\t\tassert.Equal(t, tc.expected, result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestGetColorNameFromCode(t *testing.T) {\n\tcases := []struct {\n\t\texpected  string\n\t\tcolorCode int\n\t}{\n\t\t{\"black\", 30},\n\t\t{\"red\", 31},\n\t\t{\"green\", 32},\n\t\t{\"yellow\", 33},\n\t\t{\"blue\", 34},\n\t\t{\"magenta\", 35},\n\t\t{\"cyan\", 36},\n\t\t{\"white\", 37},\n\t\t{\"black\", 40}, // background\n\t\t{\"red\", 41},   // background\n\t\t{\"darkGray\", 90},\n\t\t{\"lightRed\", 91},\n\t\t{\"lightGreen\", 92},\n\t\t{\"lightYellow\", 93},\n\t\t{\"lightBlue\", 94},\n\t\t{\"lightMagenta\", 95},\n\t\t{\"lightCyan\", 96},\n\t\t{\"lightWhite\", 97},\n\t\t{\"\", 999}, // invalid code\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.expected, func(t *testing.T) {\n\t\t\tresult := colorNameFromCode(tc.colorCode)\n\t\t\tassert.Equal(t, tc.expected, result)\n\t\t})\n\t}\n}\n\nfunc TestSetBase16Color(t *testing.T) {\n\tcases := []struct {\n\t\tcolorOverrides     map[string]HexColor\n\t\texpectedForeground *RGB\n\t\texpectedBackground *RGB\n\t\tname               string\n\t\tcolorCode          string\n\t}{\n\t\t{\n\t\t\tname:               \"Red foreground with override\",\n\t\t\tcolorCode:          \"31\",\n\t\t\tcolorOverrides:     map[string]HexColor{\"red\": \"#FF6B6B\", \"blue\": \"#4ECDC4\"},\n\t\t\texpectedForeground: &RGB{255, 107, 107},\n\t\t\texpectedBackground: nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"Blue background with override\",\n\t\t\tcolorCode:          \"44\",\n\t\t\tcolorOverrides:     map[string]HexColor{\"red\": \"#FF6B6B\", \"blue\": \"#4ECDC4\"},\n\t\t\texpectedForeground: nil,\n\t\t\texpectedBackground: &RGB{78, 205, 196},\n\t\t},\n\t\t{\n\t\t\tname:               \"Green foreground without override\",\n\t\t\tcolorCode:          \"32\",\n\t\t\tcolorOverrides:     map[string]HexColor{\"red\": \"#FF6B6B\", \"blue\": \"#4ECDC4\"},\n\t\t\texpectedForeground: &RGB{57, 181, 74},\n\t\t\texpectedBackground: nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"Red foreground without any overrides\",\n\t\t\tcolorCode:          \"31\",\n\t\t\tcolorOverrides:     nil,\n\t\t\texpectedForeground: &RGB{222, 56, 43},\n\t\t\texpectedBackground: nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"Blue background without any overrides\",\n\t\t\tcolorCode:          \"44\",\n\t\t\tcolorOverrides:     nil,\n\t\t\texpectedForeground: nil,\n\t\t\texpectedBackground: &RGB{0, 111, 184},\n\t\t},\n\t\t{\n\t\t\tname:               \"Invalid color code\",\n\t\t\tcolorCode:          \"invalid\",\n\t\t\tcolorOverrides:     nil,\n\t\t\texpectedForeground: &RGB{255, 255, 255},\n\t\t\texpectedBackground: nil,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\trenderer := &Renderer{\n\t\t\t\tdefaultForegroundColor: &RGB{255, 255, 255},\n\t\t\t\tSettings: Settings{\n\t\t\t\t\tColors: tc.colorOverrides,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\trenderer.setBase16Color(tc.colorCode)\n\n\t\t\tif tc.expectedForeground != nil {\n\t\t\t\tassert.Equal(t, tc.expectedForeground, renderer.foregroundColor)\n\t\t\t}\n\n\t\t\tif tc.expectedBackground != nil {\n\t\t\t\tassert.Equal(t, tc.expectedBackground, renderer.backgroundColor)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestProcessAnsiSequence(t *testing.T) {\n\tcases := []struct {\n\t\texpectedForegroundColor *RGB\n\t\texpectedBackgroundColor *RGB\n\t\tcolorOverrides          map[string]HexColor\n\t\tname                    string\n\t\tansiString              string\n\t\texpectedAnsiString      string\n\t\texpectedStyle           string\n\t}{\n\t\t{\n\t\t\tname:               \"Regular character\",\n\t\t\tansiString:         \"hello\",\n\t\t\texpectedAnsiString: \"hello\",\n\t\t},\n\t\t{\n\t\t\tname:                    \"Inverted color\",\n\t\t\tansiString:              \"\\x1b[38;2;255;0;0;49m\\x1b[7mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{21, 21, 21}, // defaultBackgroundColor\n\t\t\texpectedBackgroundColor: &RGB{255, 0, 0},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Inverted color single\",\n\t\t\tansiString:              \"\\x1b[31;49m\\x1b[7mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{21, 21, 21},  // defaultBackgroundColor\n\t\t\texpectedBackgroundColor: &RGB{222, 56, 43}, // red background (31 + 10 = 41)\n\t\t},\n\t\t{\n\t\t\tname:                    \"Full color\",\n\t\t\tansiString:              \"\\x1b[48;2;100;200;50m\\x1b[38;2;255;0;0mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedBackgroundColor: &RGB{100, 200, 50},\n\t\t\texpectedForegroundColor: &RGB{255, 0, 0},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Foreground color\",\n\t\t\tansiString:              \"\\x1b[38;2;255;128;0mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{255, 128, 0},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Background color\",\n\t\t\tansiString:              \"\\x1b[48;2;0;255;128mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedBackgroundColor: &RGB{0, 255, 128},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Reset sequence\",\n\t\t\tansiString:              \"\\x1b[0mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{255, 255, 255}, // defaultForegroundColor\n\t\t\texpectedBackgroundColor: nil,\n\t\t},\n\t\t{\n\t\t\tname:                    \"Background reset\",\n\t\t\tansiString:              \"\\x1b[49mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedBackgroundColor: nil,\n\t\t},\n\t\t{\n\t\t\tname:               \"Bold style\",\n\t\t\tansiString:         \"\\x1b[1mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"bold\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Italic style\",\n\t\t\tansiString:         \"\\x1b[3mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"italic\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Underline style\",\n\t\t\tansiString:         \"\\x1b[4mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"underline\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Overline style\",\n\t\t\tansiString:         \"\\x1b[53mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"overline\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Bold reset\",\n\t\t\tansiString:         \"\\x1b[22mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Italic reset\",\n\t\t\tansiString:         \"\\x1b[23mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Underline reset\",\n\t\t\tansiString:         \"\\x1b[24mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Overline reset\",\n\t\t\tansiString:         \"\\x1b[55mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t\texpectedStyle:      \"\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Strikethrough\",\n\t\t\tansiString:         \"\\x1b[9mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Strikethrough reset\",\n\t\t\tansiString:         \"\\x1b[29mtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Left cursor movement\",\n\t\t\tansiString:         \"\\x1b[5Dtest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Line change\",\n\t\t\tansiString:         \"\\x1b[2Ftest\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t},\n\t\t{\n\t\t\tname:               \"Console title\",\n\t\t\tansiString:         \"\\x1b]0;My Title\\007test\",\n\t\t\texpectedAnsiString: \"test\",\n\t\t},\n\t\t{\n\t\t\tname:                    \"Base16 red color\",\n\t\t\tansiString:              \"\\x1b[31mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{222, 56, 43},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Base16 blue background\",\n\t\t\tansiString:              \"\\x1b[44mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedBackgroundColor: &RGB{0, 111, 184},\n\t\t},\n\t\t{\n\t\t\tname:                    \"Base16 red with override\",\n\t\t\tansiString:              \"\\x1b[31mtest\",\n\t\t\texpectedAnsiString:      \"test\",\n\t\t\texpectedForegroundColor: &RGB{255, 107, 107},\n\t\t\tcolorOverrides:          map[string]HexColor{\"red\": \"#FF6B6B\"},\n\t\t},\n\t\t{\n\t\t\tname:               \"Link sequence\",\n\t\t\tansiString:         \"\\x1b]8;;https://example.com\\x1b\\\\Click here\\x1b]8;;\\x1b\\\\test\",\n\t\t\texpectedAnsiString: \"Click heretest\",\n\t\t},\n\t\t{\n\t\t\tname:               \"No matching sequence\",\n\t\t\tansiString:         \"plain text\",\n\t\t\texpectedAnsiString: \"plain text\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\trenderer := &Renderer{\n\t\t\t\tAnsiString: tc.ansiString,\n\t\t\t\tSettings: Settings{\n\t\t\t\t\tColors: tc.colorOverrides,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\trenderer.initDefaults()\n\n\t\t\tvar result bool\n\t\t\tfor !result {\n\t\t\t\tresult = renderer.processAnsiSequence()\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.expectedAnsiString, renderer.AnsiString)\n\n\t\t\tif tc.expectedForegroundColor != nil {\n\t\t\t\tassert.Equal(t, tc.expectedForegroundColor, renderer.foregroundColor)\n\t\t\t}\n\n\t\t\tif tc.expectedBackgroundColor != nil {\n\t\t\t\tassert.Equal(t, tc.expectedBackgroundColor, renderer.backgroundColor)\n\t\t\t}\n\n\t\t\tif tc.expectedStyle != \"\" {\n\t\t\t\tassert.Equal(t, tc.expectedStyle, renderer.style)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/cli/init.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/pflag\"\n)\n\nvar (\n\tprintOutput bool\n\tstrict      bool\n\tdebug       bool\n\n\tsupportedShells = []string{\n\t\t\"bash\",\n\t\t\"zsh\",\n\t\t\"fish\",\n\t\t\"powershell\",\n\t\t\"pwsh\",\n\t\t\"cmd\",\n\t\t\"nu\",\n\t\t\"elvish\",\n\t\t\"xonsh\",\n\t}\n\n\tinitCmd = createInitCmd()\n)\n\nfunc init() {\n\tRootCmd.AddCommand(initCmd)\n}\n\nfunc createInitCmd() *cobra.Command {\n\tinitCmd := &cobra.Command{\n\t\tUse:   \"init [bash|zsh|fish|powershell|pwsh|cmd|nu|elvish|xonsh]\",\n\t\tShort: \"Initialize your shell and config\",\n\t\tLong: `Initialize your shell and config.\n\nSee the documentation to initialize your shell: https://ohmyposh.dev/docs/installation/prompt.`,\n\t\tValidArgs: supportedShells,\n\t\tArgs:      NoArgsOrOneValidArg,\n\t\tRun: func(cmd *cobra.Command, args []string) {\n\t\t\tif len(args) == 0 {\n\t\t\t\t_ = cmd.Help()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trunInit(args[0], getFullCommand(cmd, args))\n\t\t},\n\t}\n\n\tinitCmd.Flags().BoolVarP(&printOutput, \"print\", \"p\", false, \"print the init script\")\n\tinitCmd.Flags().BoolVarP(&strict, \"strict\", \"s\", false, \"run in strict mode\")\n\tinitCmd.Flags().BoolVar(&debug, \"debug\", false, \"enable/disable debug mode\")\n\tinitCmd.Flags().BoolVar(&eval, \"eval\", false, \"output the full init script for eval\")\n\n\t_ = initCmd.MarkPersistentFlagRequired(\"config\")\n\n\treturn initCmd\n}\n\nfunc runInit(sh, command string) {\n\tif os.Getenv(\"CURSOR_AGENT\") == \"1\" {\n\t\tlog.Errorf(\"oh-my-posh init is disabled when running inside Cursor agent mode\")\n\t\treturn\n\t}\n\n\tif debug {\n\t\tlog.Enable(plain)\n\t}\n\n\tif sh == \"powershell\" {\n\t\tsh = shell.PWSH\n\t}\n\n\tinitCache(sh)\n\n\tcfg := config.Load(configFlag)\n\n\tflags := &runtime.Flags{\n\t\tShell:      sh,\n\t\tConfigPath: cfg.Source,\n\t\tConfigHash: cfg.Hash(),\n\t\tStrict:     strict,\n\t\tDebug:      debug,\n\t\tInit:       true,\n\t\tEval:       eval,\n\t\tPlain:      plain,\n\t}\n\n\tenv := &runtime.Terminal{}\n\tenv.Init(flags)\n\n\ttemplate.Init(env, cfg.Var, cfg.Maps)\n\n\tdefer func() {\n\t\tcfg.Store()\n\t\ttemplate.SaveCache()\n\t\tif err := cache.Clear(false, shell.InitScriptName(env.Flags())); err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t\tcache.Close()\n\t}()\n\n\tfeats := cfg.Features(env)\n\n\tvar output string\n\n\tswitch {\n\tcase debug:\n\t\toutput = shell.Debug(env, feats, &startTime)\n\tcase printOutput:\n\t\toutput = shell.Script(env, feats)\n\tdefault:\n\t\toutput = shell.Init(env, feats)\n\t}\n\n\tshellDSC := shell.DSC()\n\tshellDSC.Load()\n\tshellDSC.Add(&shell.Shell{\n\t\tCommand: command,\n\t\tName:    sh,\n\t})\n\tshellDSC.Save()\n\n\tif silent {\n\t\treturn\n\t}\n\n\tfmt.Print(output)\n}\n\nfunc getFullCommand(cmd *cobra.Command, args []string) string {\n\t// Start with the command path\n\tcmdPath := cmd.CommandPath()\n\n\t// Add arguments\n\tif len(args) > 0 {\n\t\tcmdPath += \" \" + strings.Join(args, \" \")\n\t}\n\n\t// Add flags that were actually set\n\tcmd.Flags().VisitAll(func(flag *pflag.Flag) {\n\t\tif !flag.Changed {\n\t\t\treturn\n\t\t}\n\n\t\tif flag.Value.Type() == \"bool\" && flag.Value.String() == \"true\" {\n\t\t\tcmdPath += fmt.Sprintf(\" --%s\", flag.Name)\n\t\t\treturn\n\t\t}\n\n\t\tif flag.Name == \"config\" {\n\t\t\tconfigPath := filepath.Clean(flag.Value.String())\n\t\t\tconfigPath = strings.ReplaceAll(configPath, path.Home(), \"~\")\n\t\t\tcmdPath += fmt.Sprintf(\" --%s=%s\", flag.Name, configPath)\n\t\t\treturn\n\t\t}\n\n\t\tcmdPath += fmt.Sprintf(\" --%s=%s\", flag.Name, flag.Value.String())\n\t})\n\n\treturn cmdPath\n}\n\nfunc initCache(sh string) {\n\tswitch {\n\tcase !printOutput:\n\t\tif (eval && sh == shell.PWSH) || sh == shell.ELVISH {\n\t\t\tcache.Init(sh)\n\t\t\treturn\n\t\t}\n\n\t\tfallthrough\n\tdefault:\n\t\tcache.Init(sh, cache.NewSession, cache.Persist)\n\t}\n}\n"
  },
  {
    "path": "src/cli/notice.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/spf13/cobra\"\n)\n\n// noticeCmd represents the notice command\nvar noticeCmd = &cobra.Command{\n\tUse:   \"notice\",\n\tShort: \"Print the upgrade notice when a new version is available.\",\n\tLong:  \"Print the upgrade notice when a new version is available.\",\n\tArgs:  cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(&runtime.Flags{})\n\n\t\tcache.Init(os.Getenv(\"POSH_SHELL\"), cache.Persist)\n\n\t\tdefer func() {\n\t\t\tcache.Close()\n\t\t}()\n\n\t\tcfg := config.Get(configFlag, false)\n\n\t\tif notice, hasNotice := cfg.Upgrade.Notice(); hasNotice {\n\t\t\tfmt.Println(notice)\n\t\t}\n\t},\n}\n\nfunc init() {\n\tRootCmd.AddCommand(noticeCmd)\n}\n"
  },
  {
    "path": "src/cli/print.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tpwd           string\n\tpswd          string\n\tstatus        int\n\tpipestatus    string\n\ttiming        float64\n\tstackCount    int\n\tterminalWidth int\n\teval          bool\n\tcleared       bool\n\tjobCount      int\n\tsaveCache     bool\n\n\tcommand      string\n\tshellVersion string\n\tplain        bool\n\tnoStatus     bool\n\tcolumn       int\n\tescape       bool\n)\n\n// printCmd represents the print command\nvar printCmd = createPrintCmd()\n\nfunc init() {\n\tRootCmd.AddCommand(printCmd)\n}\n\nfunc createPrintCmd() *cobra.Command {\n\tprintCmd := &cobra.Command{\n\t\tUse:   \"print [debug|primary|secondary|transient|right|tooltip|valid|error|preview]\",\n\t\tShort: \"Print the prompt/context\",\n\t\tLong:  \"Print one of the prompts based on the location/use-case.\",\n\t\tValidArgs: []string{\n\t\t\tprompt.DEBUG,\n\t\t\tprompt.PRIMARY,\n\t\t\tprompt.SECONDARY,\n\t\t\tprompt.TRANSIENT,\n\t\t\tprompt.RIGHT,\n\t\t\tprompt.TOOLTIP,\n\t\t\tprompt.VALID,\n\t\t\tprompt.ERROR,\n\t\t\tprompt.PREVIEW,\n\t\t},\n\t\tArgs: NoArgsOrOneValidArg,\n\t\tRun: func(cmd *cobra.Command, args []string) {\n\t\t\tif len(args) == 0 {\n\t\t\t\t_ = cmd.Help()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif shellName == \"\" {\n\t\t\t\tshellName = shell.GENERIC\n\t\t\t}\n\n\t\t\tflags := &runtime.Flags{\n\t\t\t\tConfigPath:    configFlag,\n\t\t\t\tPWD:           pwd,\n\t\t\t\tPSWD:          pswd,\n\t\t\t\tErrorCode:     status,\n\t\t\t\tPipeStatus:    pipestatus,\n\t\t\t\tExecutionTime: timing,\n\t\t\t\tStackCount:    stackCount,\n\t\t\t\tTerminalWidth: terminalWidth,\n\t\t\t\tEval:          eval,\n\t\t\t\tShell:         shellName,\n\t\t\t\tShellVersion:  shellVersion,\n\t\t\t\tPlain:         plain,\n\t\t\t\tType:          args[0],\n\t\t\t\tCleared:       cleared,\n\t\t\t\tNoExitCode:    noStatus,\n\t\t\t\tColumn:        column,\n\t\t\t\tJobCount:      jobCount,\n\t\t\t\tIsPrimary:     args[0] == prompt.PRIMARY,\n\t\t\t\tEscape:        escape,\n\t\t\t\tForce:         force,\n\t\t\t}\n\n\t\t\toptions := []cache.Option{}\n\t\t\tif saveCache {\n\t\t\t\toptions = append(options, cache.Persist)\n\t\t\t}\n\n\t\t\tcache.Init(shellName, options...)\n\n\t\t\teng := prompt.New(flags)\n\n\t\t\tdefer func() {\n\t\t\t\ttemplate.SaveCache()\n\t\t\t\tcache.Close()\n\t\t\t}()\n\n\t\t\tswitch args[0] {\n\t\t\tcase prompt.DEBUG:\n\t\t\t\tfmt.Print(eng.ExtraPrompt(prompt.Debug))\n\t\t\tcase prompt.PRIMARY:\n\t\t\t\tfmt.Print(eng.Primary())\n\t\t\tcase prompt.SECONDARY:\n\t\t\t\tfmt.Print(eng.ExtraPrompt(prompt.Secondary))\n\t\t\tcase prompt.TRANSIENT:\n\t\t\t\tfmt.Print(eng.ExtraPrompt(prompt.Transient))\n\t\t\tcase prompt.RIGHT:\n\t\t\t\tfmt.Print(eng.RPrompt())\n\t\t\tcase prompt.TOOLTIP:\n\t\t\t\tfmt.Print(eng.Tooltip(command))\n\t\t\tcase prompt.VALID:\n\t\t\t\tfmt.Print(eng.ExtraPrompt(prompt.Valid))\n\t\t\tcase prompt.ERROR:\n\t\t\t\tfmt.Print(eng.ExtraPrompt(prompt.Error))\n\t\t\tcase prompt.PREVIEW:\n\t\t\t\tfmt.Print(eng.Preview())\n\t\t\tdefault:\n\t\t\t\t_ = cmd.Help()\n\t\t\t}\n\t\t},\n\t}\n\n\tprintCmd.Flags().StringVar(&pwd, \"pwd\", \"\", \"current working directory\")\n\tprintCmd.Flags().StringVar(&pswd, \"pswd\", \"\", \"current working directory (according to pwsh)\")\n\tprintCmd.Flags().StringVar(&shellName, \"shell\", \"\", \"the shell to print for\")\n\tprintCmd.Flags().StringVar(&shellVersion, \"shell-version\", \"\", \"the shell version\")\n\tprintCmd.Flags().IntVar(&status, \"status\", 0, \"last known status code\")\n\tprintCmd.Flags().BoolVar(&noStatus, \"no-status\", false, \"no valid status code (cancelled or no command yet)\")\n\tprintCmd.Flags().StringVar(&pipestatus, \"pipestatus\", \"\", \"the PIPESTATUS array\")\n\tprintCmd.Flags().Float64Var(&timing, \"execution-time\", 0, \"timing of the last command\")\n\tprintCmd.Flags().IntVarP(&stackCount, \"stack-count\", \"s\", 0, \"number of locations on the stack\")\n\tprintCmd.Flags().IntVarP(&terminalWidth, \"terminal-width\", \"w\", 0, \"width of the terminal\")\n\tprintCmd.Flags().StringVar(&command, \"command\", \"\", \"tooltip command\")\n\tprintCmd.Flags().BoolVar(&cleared, \"cleared\", false, \"do we have a clear terminal or not\")\n\tprintCmd.Flags().BoolVar(&eval, \"eval\", false, \"output the prompt for eval\")\n\tprintCmd.Flags().IntVar(&column, \"column\", 0, \"the column position of the cursor\")\n\tprintCmd.Flags().IntVar(&jobCount, \"job-count\", 0, \"number of background jobs\")\n\tprintCmd.Flags().BoolVar(&saveCache, \"save-cache\", false, \"save updated cache to file\")\n\tprintCmd.Flags().BoolVar(&escape, \"escape\", true, \"escape the ANSI sequences for the shell\")\n\tprintCmd.Flags().BoolVarP(&force, \"force\", \"f\", false, \"force rendering the segments\")\n\n\t// Hide flags that are for internal use only.\n\t_ = printCmd.Flags().MarkHidden(\"save-cache\")\n\n\treturn printCmd\n}\n"
  },
  {
    "path": "src/cli/progress/model.go",
    "content": "package progress\n\nimport (\n\t\"github.com/charmbracelet/bubbles/progress\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\ntype Message float64\n\nfunc NewModel() *Model {\n\tp := progress.New(progress.WithScaledGradient(\"#800080\", \"#ffc0cb\"))\n\treturn &Model{Model: p}\n}\n\ntype Model struct {\n\tprogress.Model\n}\n\nfunc (m *Model) Update(msg tea.Msg) tea.Cmd {\n\tmodel, cmd := m.Model.Update(msg)\n\tm.Model = model.(progress.Model)\n\n\treturn cmd\n}\n\nfunc (m *Model) View() string {\n\treturn m.Model.View() + terminal.SetProgress(int(m.Percent()*100))\n}\n"
  },
  {
    "path": "src/cli/progress/reader.go",
    "content": "package progress\n\nimport (\n\t\"io\"\n\n\ttea \"github.com/charmbracelet/bubbletea\"\n)\n\nfunc NewReader(reader io.Reader, total int64, program *tea.Program) *Reader {\n\treturn &Reader{\n\t\tReader:  reader,\n\t\tprogram: program,\n\t\ttotal:   total,\n\t}\n}\n\ntype Reader struct {\n\tio.Reader\n\n\tprogram *tea.Program\n\ttotal   int64\n\tcurrent int64\n}\n\nfunc (r *Reader) Read(p []byte) (int, error) {\n\tn, err := r.Reader.Read(p)\n\tr.current += int64(n)\n\tpercent := float64(r.current) / float64(r.total)\n\n\tif r.program != nil {\n\t\tr.program.Send(Message(percent))\n\t}\n\n\treturn n, err\n}\n"
  },
  {
    "path": "src/cli/root.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tconfigFlag   string\n\tshellName    string\n\tprintVersion bool\n\ttrace        bool\n\texitcode     int\n\n\t// for internal use only\n\tsilent bool\n\n\t// deprecated\n\tinitialize bool\n)\n\nvar RootCmd = &cobra.Command{\n\tUse:   \"oh-my-posh\",\n\tShort: \"oh-my-posh is a tool to render your prompt\",\n\tLong: `oh-my-posh is a cross platform tool to render your prompt.\nIt can use the same configuration everywhere to offer a consistent\nexperience, regardless of where you are. For a detailed guide\non getting started, have a look at the docs at https://ohmyposh.dev`,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif initialize {\n\t\t\trunInit(strings.ToLower(shellName), getFullCommand(cmd, args))\n\t\t\treturn\n\t\t}\n\n\t\tif printVersion {\n\t\t\tfmt.Println(build.Version)\n\t\t\treturn\n\t\t}\n\n\t\t_ = cmd.Help()\n\t},\n\tPersistentPreRun: func(cmd *cobra.Command, args []string) {\n\t\tconfigEnv := os.Getenv(\"POSH_CONFIG\")\n\t\tif configEnv != \"\" && configFlag == \"\" {\n\t\t\tconfigFlag = configEnv\n\t\t}\n\n\t\ttraceEnv := os.Getenv(\"POSH_TRACE\")\n\t\tif traceEnv == \"\" && !trace {\n\t\t\treturn\n\t\t}\n\n\t\ttrace = true\n\n\t\tlog.Enable(true)\n\n\t\tlog.Debug(\"version:\", build.Version)\n\t\tlog.Debug(\"command:\", getFullCommand(cmd, args))\n\t},\n\tPersistentPostRun: func(cmd *cobra.Command, args []string) {\n\t\tdefer func() {\n\t\t\tif exitcode != 0 {\n\t\t\t\tos.Exit(exitcode)\n\t\t\t}\n\t\t}()\n\n\t\tif !trace {\n\t\t\treturn\n\t\t}\n\n\t\tvar prefix string\n\t\tif shellName != \"\" {\n\t\t\tprefix = fmt.Sprintf(\"%s-\", shellName)\n\t\t}\n\n\t\tcli := append([]string{cmd.Name()}, args...)\n\n\t\tfilename := fmt.Sprintf(\"%s-%s%s.log\", time.Now().Format(\"02012006T150405.000\"), prefix, strings.Join(cli, \"-\"))\n\n\t\tlogPath := filepath.Join(cache.Path(), \"logs\")\n\t\terr := os.MkdirAll(logPath, 0755)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\n\t\terr = os.WriteFile(filepath.Join(logPath, filename), []byte(log.String()), 0644)\n\t\tif err != nil {\n\t\t\treturn\n\t\t}\n\t},\n}\n\nfunc Execute() {\n\tif err := RootCmd.Execute(); err != nil {\n\t\t// software error\n\t\tos.Exit(70)\n\t}\n}\n\nfunc init() {\n\tRootCmd.PersistentFlags().StringVarP(&configFlag, \"config\", \"c\", \"\", \"config file path\")\n\tRootCmd.PersistentFlags().BoolVar(&silent, \"silent\", false, \"do not print anything\")\n\tRootCmd.PersistentFlags().BoolVar(&trace, \"trace\", false, \"enable tracing\")\n\tRootCmd.PersistentFlags().BoolVar(&plain, \"plain\", false, \"plain text output (no ANSI)\")\n\tRootCmd.Flags().BoolVar(&printVersion, \"version\", false, \"print the version number and exit\")\n\n\t// Deprecated flags, should be kept to avoid breaking CLI integration.\n\tRootCmd.Flags().BoolVarP(&initialize, \"init\", \"i\", false, \"init\")\n\tRootCmd.Flags().StringVarP(&shellName, \"shell\", \"s\", \"\", \"shell\")\n\n\t// Hide flags that are deprecated or for internal use only.\n\t_ = RootCmd.PersistentFlags().MarkHidden(\"silent\")\n\n\t// Disable completions\n\tRootCmd.CompletionOptions.DisableDefaultCmd = true\n}\n"
  },
  {
    "path": "src/cli/shell.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/spf13/cobra\"\n)\n\n// shellCmd represents the shell command\nvar shellCmd = &cobra.Command{\n\tUse:   \"shell get\",\n\tShort: \"Get the shell name\",\n\tLong: `Get the shell name.\n\nThis command retrieves the name of the current shell being used.`,\n\tExample: `  oh-my-posh shell get`,\n\tValidArgs: []string{\n\t\t\"get\",\n\t},\n\tArgs: NoArgsOrOneValidArg,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tflags := &runtime.Flags{\n\t\t\tShell: os.Getenv(\"POSH_SHELL\"),\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(flags)\n\n\t\tswitch args[0] {\n\t\tcase \"get\":\n\t\t\tfmt.Print(env.Shell())\n\t\tdefault:\n\t\t\t_ = cmd.Help()\n\t\t}\n\t},\n}\n\nfunc init() {\n\tshellCmd.AddCommand(dsc.Command(shell.DSC()))\n\tRootCmd.AddCommand(shellCmd)\n}\n"
  },
  {
    "path": "src/cli/stream.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// streamCmd represents the stream command\nvar streamCmd = createStreamCmd()\n\nfunc init() {\n\tRootCmd.AddCommand(streamCmd)\n}\n\nfunc createStreamCmd() *cobra.Command {\n\tstreamCmd := &cobra.Command{\n\t\tUse:   \"stream\",\n\t\tShort: \"Stream the prompt with incremental updates\",\n\t\tLong: `Stream the primary prompt with incremental updates as segments complete.\nOutput format: null-byte delimited prompt strings (each complete prompt separated by \\0).\nThis allows multi-line prompts to be handled correctly.\nThe shell can read records incrementally and update the display.\nCommand exits when all segments are resolved.`,\n\t\tArgs: cobra.NoArgs,\n\t\tRun: func(_ *cobra.Command, _ []string) {\n\t\t\tif shellName == \"\" {\n\t\t\t\tshellName = shell.GENERIC\n\t\t\t}\n\n\t\t\tflags := &runtime.Flags{\n\t\t\t\tConfigPath:    configFlag,\n\t\t\t\tPWD:           pwd,\n\t\t\t\tPSWD:          pswd,\n\t\t\t\tErrorCode:     status,\n\t\t\t\tPipeStatus:    pipestatus,\n\t\t\t\tExecutionTime: timing,\n\t\t\t\tStackCount:    stackCount,\n\t\t\t\tTerminalWidth: terminalWidth,\n\t\t\t\tEval:          eval,\n\t\t\t\tShell:         shellName,\n\t\t\t\tShellVersion:  shellVersion,\n\t\t\t\tPlain:         plain,\n\t\t\t\tType:          prompt.PRIMARY,\n\t\t\t\tCleared:       cleared,\n\t\t\t\tNoExitCode:    noStatus,\n\t\t\t\tColumn:        column,\n\t\t\t\tJobCount:      jobCount,\n\t\t\t\tIsPrimary:     true,\n\t\t\t\tEscape:        escape,\n\t\t\t\tForce:         force,\n\t\t\t\tStreaming:     true,\n\t\t\t}\n\n\t\t\toptions := []cache.Option{}\n\t\t\tif saveCache {\n\t\t\t\toptions = append(options, cache.Persist)\n\t\t\t}\n\n\t\t\tcache.Init(shellName, options...)\n\n\t\t\teng := prompt.New(flags)\n\n\t\t\tdefer func() {\n\t\t\t\ttemplate.SaveCache()\n\t\t\t\tcache.Close()\n\t\t\t}()\n\n\t\t\t// Stream prompt updates\n\t\t\tfor promptString := range eng.StreamPrimary() {\n\t\t\t\tfmt.Print(promptString)\n\t\t\t\tfmt.Print(\"\\x00\") // Null byte delimiter for multi-line prompts\n\t\t\t}\n\t\t},\n\t}\n\n\tstreamCmd.Flags().StringVar(&pwd, \"pwd\", \"\", \"current working directory\")\n\tstreamCmd.Flags().StringVar(&pswd, \"pswd\", \"\", \"current working directory (according to pwsh)\")\n\tstreamCmd.Flags().StringVar(&shellName, \"shell\", \"\", \"the shell to stream for\")\n\tstreamCmd.Flags().StringVar(&shellVersion, \"shell-version\", \"\", \"the shell version\")\n\tstreamCmd.Flags().IntVar(&status, \"status\", 0, \"last known status code\")\n\tstreamCmd.Flags().BoolVar(&noStatus, \"no-status\", false, \"no valid status code (cancelled or no command yet)\")\n\tstreamCmd.Flags().StringVar(&pipestatus, \"pipestatus\", \"\", \"the PIPESTATUS array\")\n\tstreamCmd.Flags().Float64Var(&timing, \"execution-time\", 0, \"timing of the last command\")\n\tstreamCmd.Flags().IntVarP(&stackCount, \"stack-count\", \"s\", 0, \"number of locations on the stack\")\n\tstreamCmd.Flags().IntVarP(&terminalWidth, \"terminal-width\", \"w\", 0, \"width of the terminal\")\n\tstreamCmd.Flags().BoolVar(&cleared, \"cleared\", false, \"do we have a clear terminal or not\")\n\tstreamCmd.Flags().BoolVar(&eval, \"eval\", false, \"output the prompt for eval\")\n\tstreamCmd.Flags().IntVar(&column, \"column\", 0, \"the column position of the cursor\")\n\tstreamCmd.Flags().IntVar(&jobCount, \"job-count\", 0, \"number of background jobs\")\n\tstreamCmd.Flags().BoolVar(&saveCache, \"save-cache\", false, \"save updated cache to file\")\n\tstreamCmd.Flags().BoolVar(&escape, \"escape\", true, \"escape the ANSI sequences for the shell\")\n\tstreamCmd.Flags().BoolVarP(&force, \"force\", \"f\", false, \"force rendering the segments\")\n\n\t// Hide flags that are for internal use only.\n\t_ = streamCmd.Flags().MarkHidden(\"save-cache\")\n\n\treturn streamCmd\n}\n"
  },
  {
    "path": "src/cli/stream_test.go",
    "content": "package cli\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestStreamCommand_Creation(t *testing.T) {\n\tcmd := createStreamCmd()\n\n\tassert.NotNil(t, cmd)\n\tassert.Equal(t, \"stream\", cmd.Use)\n\tassert.Equal(t, \"Stream the prompt with incremental updates\", cmd.Short)\n}\n\nfunc TestStreamCommand_Flags(t *testing.T) {\n\tcmd := createStreamCmd()\n\n\t// Verify all expected flags exist\n\texpectedFlags := []string{\n\t\t\"pwd\",\n\t\t\"pswd\",\n\t\t\"shell\",\n\t\t\"shell-version\",\n\t\t\"status\",\n\t\t\"no-status\",\n\t\t\"pipestatus\",\n\t\t\"execution-time\",\n\t\t\"stack-count\",\n\t\t\"terminal-width\",\n\t\t\"cleared\",\n\t\t\"eval\",\n\t\t\"column\",\n\t\t\"job-count\",\n\t\t\"save-cache\",\n\t\t\"escape\",\n\t\t\"force\",\n\t}\n\n\tfor _, flagName := range expectedFlags {\n\t\tflag := cmd.Flags().Lookup(flagName)\n\t\tassert.NotNil(t, flag, \"Flag '%s' should exist\", flagName)\n\t}\n}\n\nfunc TestStreamCommand_RequiredFlagsForStreaming(t *testing.T) {\n\t// This test validates that the stream command sets the correct flags\n\t// for streaming execution mode\n\n\tcmd := createStreamCmd()\n\n\t// Verify that running the command would set streaming=true\n\t// We can't easily test the actual run without a full config,\n\t// but we can verify the command is properly configured\n\tassert.NotNil(t, cmd.Run)\n\tassert.NotNil(t, cmd.Args)\n}\n\nfunc TestStreamCommand_FlagInheritance(t *testing.T) {\n\t// Verify that stream command uses the same flags as print command\n\t// This ensures consistency between commands\n\n\tstreamCmd := createStreamCmd()\n\tprintCmd := createPrintCmd()\n\n\t// Core flags that should exist in both\n\tsharedFlags := []string{\n\t\t\"pwd\",\n\t\t\"shell\",\n\t\t\"status\",\n\t\t\"execution-time\",\n\t\t\"terminal-width\",\n\t\t\"eval\",\n\t\t\"force\",\n\t}\n\n\tfor _, flagName := range sharedFlags {\n\t\tstreamFlag := streamCmd.Flags().Lookup(flagName)\n\t\tprintFlag := printCmd.Flags().Lookup(flagName)\n\n\t\tassert.NotNil(t, streamFlag, \"Stream command should have '%s' flag\", flagName)\n\t\tassert.NotNil(t, printFlag, \"Print command should have '%s' flag\", flagName)\n\n\t\t// Verify default values match\n\t\tif streamFlag != nil && printFlag != nil {\n\t\t\tassert.Equal(t, printFlag.DefValue, streamFlag.DefValue,\n\t\t\t\t\"Flag '%s' should have same default value in both commands\", flagName)\n\t\t}\n\t}\n}\n\nfunc TestStreamCommand_OutputDelimiter(t *testing.T) {\n\t// Test that output uses null byte delimiter for multi-line prompts\n\ttests := []struct {\n\t\tname     string\n\t\texpected string\n\t\tprompts  []string\n\t}{\n\t\t{\n\t\t\tname:     \"Single line prompt\",\n\t\t\tprompts:  []string{\"prompt1\"},\n\t\t\texpected: \"prompt1\\x00\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Multi-line prompt\",\n\t\t\tprompts:  []string{\"line1\\nline2\\nline3\"},\n\t\t\texpected: \"line1\\nline2\\nline3\\x00\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Multiple prompts\",\n\t\t\tprompts:  []string{\"prompt1\", \"prompt2\", \"prompt3\"},\n\t\t\texpected: \"prompt1\\x00prompt2\\x00prompt3\\x00\",\n\t\t},\n\t\t{\n\t\t\tname:     \"Multiple multi-line prompts\",\n\t\t\tprompts:  []string{\"line1\\nline2\", \"line3\\nline4\"},\n\t\t\texpected: \"line1\\nline2\\x00line3\\nline4\\x00\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Simulate output with null byte delimiter\n\t\t\tvar buf bytes.Buffer\n\t\t\tfor _, prompt := range tt.prompts {\n\t\t\t\tbuf.WriteString(prompt)\n\t\t\t\tbuf.WriteString(\"\\x00\")\n\t\t\t}\n\n\t\t\tassert.Equal(t, tt.expected, buf.String())\n\t\t})\n\t}\n}\n\nfunc TestStreamCommand_Integration_MockOutput(t *testing.T) {\n\t// This test validates the output structure without requiring a full engine\n\t// It simulates what the stream command would output with null byte delimiter\n\n\ttests := []struct {\n\t\tvalidateOutput func(t *testing.T, output string)\n\t\tname           string\n\t\tpromptCount    int\n\t}{\n\t\t{\n\t\t\tname:        \"Single prompt with null byte\",\n\t\t\tpromptCount: 1,\n\t\t\tvalidateOutput: func(t *testing.T, output string) {\n\t\t\t\tassert.True(t, strings.HasSuffix(output, \"\\x00\"))\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname:        \"Multiple prompts with null bytes\",\n\t\t\tpromptCount: 3,\n\t\t\tvalidateOutput: func(t *testing.T, output string) {\n\t\t\t\tparts := strings.Split(output, \"\\x00\")\n\t\t\t\t// 3 prompts = 4 parts (including trailing empty string after last \\x00)\n\t\t\t\tassert.Len(t, parts, 4)\n\t\t\t\t// Last part should be empty\n\t\t\t\tassert.Equal(t, \"\", parts[3])\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\t// Simulate stream output with null byte delimiter\n\t\t\tvar output bytes.Buffer\n\t\t\tfor i := 0; i < tt.promptCount; i++ {\n\t\t\t\toutput.WriteString(\"prompt\")\n\t\t\t\toutput.WriteString(\"\\x00\")\n\t\t\t}\n\n\t\t\ttt.validateOutput(t, output.String())\n\t\t})\n\t}\n}\n\nfunc TestStreamCommand_HiddenFlags(t *testing.T) {\n\tcmd := createStreamCmd()\n\n\t// Verify save-cache is hidden (internal use only)\n\tsaveCacheFlag := cmd.Flags().Lookup(\"save-cache\")\n\trequire.NotNil(t, saveCacheFlag)\n\tassert.True(t, saveCacheFlag.Hidden, \"save-cache flag should be hidden\")\n}\n\nfunc TestStreamCommand_NoArgs(t *testing.T) {\n\tcmd := createStreamCmd()\n\n\t// Stream command should not accept positional arguments\n\t// (unlike print which accepts primary/secondary/etc.)\n\tassert.NotNil(t, cmd.Args)\n\n\t// Test that NoArgs validator rejects arguments\n\terr := cmd.Args(cmd, []string{\"extra\"})\n\tassert.Error(t, err, \"Should reject arguments when NoArgs is used\")\n\n\t// Test that NoArgs validator accepts no arguments\n\terr = cmd.Args(cmd, []string{})\n\tassert.NoError(t, err, \"Should accept no arguments\")\n}\n\nfunc TestStreamCommand_StreamingFlagEnabled(t *testing.T) {\n\t// This validates that the stream command would create\n\t// a Flags struct with Streaming=true\n\n\t// We can't easily test the full execution without mocking the entire engine,\n\t// but we can verify the command structure is correct\n\n\tcmd := createStreamCmd()\n\tassert.NotNil(t, cmd.Run)\n\n\t// The Run function should:\n\t// 1. Create Flags with Streaming=true\n\t// 2. Set Type=prompt.PRIMARY\n\t// 3. Set IsPrimary=true\n\t// These are validated by code inspection in the createStreamCmd implementation\n}\n"
  },
  {
    "path": "src/cli/toggle.go",
    "content": "package cli\n\nimport (\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/spf13/cobra\"\n)\n\n// toggleCmd represents the toggle command\nvar toggleCmd = &cobra.Command{\n\tUse:   \"toggle segment1 segment2 ...\",\n\tShort: \"Toggle one or more segments on/off\",\n\tLong:  \"Toggle one or more segments on/off on the fly. Multiple segments can be specified separated by spaces.\",\n\tArgs:  cobra.MinimumNArgs(1),\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tif len(args) == 0 {\n\t\t\t_ = cmd.Help()\n\t\t\treturn\n\t\t}\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(&runtime.Flags{})\n\n\t\tcache.Init(os.Getenv(\"POSH_SHELL\"), cache.Persist)\n\n\t\tdefer func() {\n\t\t\tcache.Close()\n\t\t}()\n\n\t\t// Get current toggles from cache as a map\n\t\tcurrentToggleSet, _ := cache.Get[map[string]bool](cache.Session, cache.TOGGLECACHE)\n\t\tif currentToggleSet == nil {\n\t\t\tcurrentToggleSet = make(map[string]bool)\n\t\t}\n\n\t\tsegmentsToToggle := parseSegments(args)\n\n\t\t// Toggle segments: remove if present, add if not present\n\t\tfor _, segment := range segmentsToToggle {\n\t\t\tif currentToggleSet[segment] {\n\t\t\t\tdelete(currentToggleSet, segment)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tcurrentToggleSet[segment] = true\n\t\t}\n\n\t\t// Store the map directly in cache\n\t\tcache.Set(cache.Session, cache.TOGGLECACHE, currentToggleSet, cache.INFINITE)\n\t},\n}\n\nfunc parseSegments(args []string) []string {\n\tvar segments []string\n\tfor _, arg := range args {\n\t\tif segment := strings.TrimSpace(arg); segment != \"\" {\n\t\t\tsegments = append(segments, segment)\n\t\t}\n\t}\n\n\treturn segments\n}\n\nfunc init() {\n\tRootCmd.AddCommand(toggleCmd)\n}\n"
  },
  {
    "path": "src/cli/upgrade/config.go",
    "content": "package upgrade\n\nimport (\n\t\"context\"\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"io\"\n\thttplib \"net/http\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/progress\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nfunc init() {\n\tgob.Register(&Config{})\n\tgob.Register((*Source)(nil))\n}\n\ntype Config struct {\n\tSource        Source         `json:\"source\" toml:\"source\" yaml:\"source\"`\n\tInterval      cache.Duration `json:\"interval\" toml:\"interval\" yaml:\"interval\"`\n\tLatest        string         `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tAuto          bool           `json:\"auto\" toml:\"auto\" yaml:\"auto\"`\n\tDisplayNotice bool           `json:\"notice\" toml:\"notice\" yaml:\"notice\"`\n\tForce         bool           `json:\"-\" toml:\"-\" yaml:\"-\"`\n}\n\ntype Source string\n\nconst (\n\tGitHub Source = \"github\"\n\tCDN    Source = \"cdn\"\n)\n\nfunc (s Source) String() string {\n\tswitch s {\n\tcase GitHub:\n\t\treturn \"github.com\"\n\tcase CDN:\n\t\treturn \"cdn.ohmyposh.dev\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\nfunc (cfg *Config) FetchLatest() (string, error) {\n\tcfg.Latest = \"latest\"\n\tv, err := cfg.DownloadAsset(\"version.txt\")\n\tif err != nil {\n\t\tlog.Debugf(\"failed to get latest version for source: %s\", cfg.Source)\n\t\treturn \"\", err\n\t}\n\n\tversion := strings.TrimSpace(string(v))\n\tcfg.Latest = version\n\n\tversion = strings.TrimPrefix(version, \"v\")\n\tlog.Debugf(\"latest version: %s\", version)\n\n\treturn version, err\n}\n\nfunc (cfg *Config) DownloadAsset(asset string) ([]byte, error) {\n\tif cfg.Source == \"\" {\n\t\tlog.Debug(\"no source specified, defaulting to github\")\n\t\tcfg.Source = GitHub\n\t}\n\n\tswitch cfg.Source {\n\tcase GitHub:\n\t\tvar url string\n\n\t\tswitch cfg.Latest {\n\t\tcase \"latest\":\n\t\t\turl = fmt.Sprintf(\"https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/%s\", asset)\n\t\tdefault:\n\t\t\turl = fmt.Sprintf(\"https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/%s/%s\", cfg.Latest, asset)\n\t\t}\n\n\t\treturn cfg.Download(url)\n\tcase CDN:\n\t\tfallthrough\n\tdefault:\n\t\turl := fmt.Sprintf(\"https://cdn.ohmyposh.dev/releases/%s/%s\", cfg.Latest, asset)\n\t\treturn cfg.Download(url)\n\t}\n}\n\nfunc (cfg *Config) Download(url string) ([]byte, error) {\n\treq, err := httplib.NewRequestWithContext(context.Background(), \"GET\", url, nil)\n\tif err != nil {\n\t\tlog.Debugf(\"failed to create request for url: %s\", url)\n\t\treturn nil, err\n\t}\n\n\treq.Header.Add(\"User-Agent\", \"oh-my-posh\")\n\treq.Header.Add(\"Cache-Control\", \"max-age=0\")\n\n\tresp, err := http.HTTPClient.Do(req)\n\tif err != nil {\n\t\tlog.Debugf(\"failed to execute HTTP request: %s\", url)\n\t\treturn nil, err\n\t}\n\n\tif resp.StatusCode != httplib.StatusOK {\n\t\treturn nil, fmt.Errorf(\"failed to download asset: %s\", url)\n\t}\n\n\tdefer resp.Body.Close()\n\n\treader := progress.NewReader(resp.Body, resp.ContentLength, program)\n\n\tdata, err := io.ReadAll(reader)\n\tif err != nil {\n\t\tlog.Debugf(\"failed to read response body: %s\", url)\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "src/cli/upgrade/install.go",
    "content": "package upgrade\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc install(cfg *Config) error {\n\tsetState(validating)\n\n\texecutable, err := os.Executable()\n\tif err != nil {\n\t\tlog.Debug(\"failed to get executable path\")\n\t\treturn err\n\t}\n\n\ttargetDir := filepath.Dir(executable)\n\tfileName := filepath.Base(executable)\n\n\tnewPath := filepath.Join(targetDir, fmt.Sprintf(\".%s.new\", fileName))\n\tfp, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn errors.New(\"we do not have permissions to update\")\n\t}\n\n\tsetState(downloading)\n\n\tdata, err := downloadAndVerify(cfg)\n\tif err != nil {\n\t\tlog.Debug(\"failed to download and verify\")\n\t\treturn err\n\t}\n\n\tsetState(installing)\n\n\t_, err = io.Copy(fp, bytes.NewReader(data))\n\t// windows will have a lock when we do not close the file\n\tfp.Close()\n\n\tif err != nil {\n\t\tlog.Debug(\"failed to copy data to new file\")\n\t\treturn err\n\t}\n\n\toldPath := filepath.Join(targetDir, fmt.Sprintf(\".%s.old\", fileName))\n\n\t_ = os.Remove(oldPath)\n\n\terr = os.Rename(executable, oldPath)\n\tif err != nil {\n\t\tlog.Debug(\"failed to rename old file\")\n\t\treturn err\n\t}\n\n\terr = os.Rename(newPath, executable)\n\n\tif err != nil {\n\t\tlog.Debug(\"failed to rename new file, rolling back\")\n\t\t// rollback\n\t\trerr := os.Rename(oldPath, executable)\n\t\tif rerr != nil {\n\t\t\tlog.Debug(\"failed to rollback old file\")\n\t\t\treturn rerr\n\t\t}\n\n\t\treturn err\n\t}\n\n\tremoveErr := os.Remove(oldPath)\n\n\t// hide the old executable if we can't remove it\n\tif removeErr != nil {\n\t\tlog.Error(removeErr)\n\t\t// hide the old executable\n\t\t_ = hideFile(oldPath)\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/cli/upgrade/install_noop.go",
    "content": "//go:build !windows\n\npackage upgrade\n\nfunc hideFile(_ string) error {\n\treturn nil\n}\n\nfunc IsPackagedInstallation() bool {\n\treturn false\n}\n"
  },
  {
    "path": "src/cli/upgrade/install_windows.go",
    "content": "package upgrade\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n)\n\nfunc hideFile(path string) error {\n\tkernel32 := syscall.NewLazyDLL(\"kernel32.dll\")\n\tsetFileAttributes := kernel32.NewProc(\"SetFileAttributesW\")\n\n\tptr, err := syscall.UTF16PtrFromString(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tr1, _, err := setFileAttributes.Call(uintptr(unsafe.Pointer(ptr)), 2)\n\n\tif r1 == 0 {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc IsPackagedInstallation() bool {\n\t_, ok := cache.PackageFamilyName()\n\treturn ok\n}\n"
  },
  {
    "path": "src/cli/upgrade/notice.go",
    "content": "package upgrade\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n)\n\nconst (\n\tCACHEKEY = \"upgrade_check\"\n\n\tupgradeNotice = `\nA new release of Oh My Posh is available: v%s → v%s\nTo upgrade, run: 'oh-my-posh upgrade%s'\n\nTo enable automated upgrades, run: 'oh-my-posh enable upgrade'.\n`\n)\n\n// Returns the upgrade notice if a new version is available\n// that should be displayed to the user.\n//\n// The upgrade check is only performed every other week.\nfunc (cfg *Config) Notice() (string, bool) {\n\t// never validate when we install using the Windows Store\n\tif os.Getenv(\"POSH_INSTALLER\") == \"ws\" {\n\t\tlog.Debug(\"skipping upgrade check because we are using the Windows Store\")\n\t\treturn \"\", false\n\t}\n\n\tif !http.IsConnected() {\n\t\treturn \"\", false\n\t}\n\n\tlatest, err := cfg.FetchLatest()\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\tif latest == build.Version {\n\t\treturn \"\", false\n\t}\n\n\tvar forceUpdate string\n\tif IsMajorUpgrade(build.Version, latest) {\n\t\tforceUpdate = \" --force\"\n\t}\n\n\treturn fmt.Sprintf(upgradeNotice, build.Version, latest, forceUpdate), true\n}\n"
  },
  {
    "path": "src/cli/upgrade/notice_test.go",
    "content": "package upgrade\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCanUpgrade(t *testing.T) {\n\tugc := &Config{}\n\tlatest, _ := ugc.FetchLatest()\n\n\tcases := []struct {\n\t\tCase           string\n\t\tCurrentVersion string\n\t\tInstaller      string\n\t\tExpected       bool\n\t\tCache          bool\n\t}{\n\t\t{Case: \"Up to date\", CurrentVersion: latest},\n\t\t{Case: \"Outdated Linux\", Expected: true, CurrentVersion: \"3.0.0\"},\n\t\t{Case: \"Outdated Darwin\", Expected: true, CurrentVersion: \"3.0.0\"},\n\t\t{Case: \"Cached\", Cache: true, CurrentVersion: latest},\n\t\t{Case: \"Windows Store\", Installer: \"ws\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tbuild.Version = tc.CurrentVersion\n\n\t\tif len(tc.Installer) > 0 {\n\t\t\tos.Setenv(\"POSH_INSTALLER\", tc.Installer)\n\t\t}\n\n\t\t_, canUpgrade := ugc.Notice()\n\t\tassert.Equal(t, tc.Expected, canUpgrade, tc.Case)\n\n\t\tos.Setenv(\"POSH_INSTALLER\", \"\")\n\t}\n}\n"
  },
  {
    "path": "src/cli/upgrade/public_key.pem",
    "content": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEA98lHhNau5x0JtjSuwiWLuC2yKO6NA6/0bH2gE8tAq4c=\n-----END PUBLIC KEY-----\n"
  },
  {
    "path": "src/cli/upgrade/tui.go",
    "content": "package upgrade\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\tprogress_ \"github.com/charmbracelet/bubbles/progress\"\n\t\"github.com/charmbracelet/bubbles/spinner\"\n\ttea \"github.com/charmbracelet/bubbletea\"\n\t\"github.com/charmbracelet/lipgloss\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/progress\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nvar (\n\tprogram   *tea.Program\n\ttextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 2)\n)\n\ntype resultMsg string\n\ntype stateMsg state\n\ntype state int\n\nconst (\n\tvalidating state = iota\n\tdownloading\n\tverifying\n\tinstalling\n)\n\nfunc setState(message state) {\n\tif program == nil {\n\t\treturn\n\t}\n\n\tprogram.Send(stateMsg(message))\n}\n\ntype model struct {\n\terror    error\n\tconfig   *Config\n\tspinner  *spinner.Model\n\tprogress *progress.Model\n\tmessage  string\n\tstate    state\n}\n\nfunc initialModel(cfg *Config) *model {\n\ts := spinner.New()\n\ts.Spinner = spinner.Dot\n\ts.Style = lipgloss.NewStyle().Foreground(lipgloss.Color(\"170\"))\n\n\tp := progress.NewModel()\n\n\treturn &model{spinner: &s, config: cfg, progress: p}\n}\n\nfunc (m *model) Init() tea.Cmd {\n\tgo m.start()\n\n\treturn m.spinner.Tick\n}\n\nfunc (m *model) start() {\n\tif err := install(m.config); err != nil {\n\t\tm.error = err\n\t\tlog.Debug(\"failed to install\")\n\t\tprogram.Send(resultMsg(fmt.Sprintf(\" ❌ upgrade failed: %v\", err)))\n\t\treturn\n\t}\n\n\tcurrent := fmt.Sprintf(\"v%s\", build.Version)\n\tmessage := fmt.Sprintf(\"🚀 Upgraded from %s to %s\", current, m.config.Latest)\n\n\tif current != m.config.Latest {\n\t\tlog.Debug(\"new version installed, user needs to restart shell\")\n\t\tmessage += \", restart your shell to take full advantage of the new functionality\"\n\t}\n\n\tprogram.Send(resultMsg(message))\n}\n\nfunc (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {\n\tswitch msg := msg.(type) {\n\tcase tea.KeyMsg:\n\t\tswitch msg.String() {\n\t\tcase \"q\", \"esc\", \"ctrl+c\":\n\t\t\treturn m, tea.Quit\n\t\tdefault:\n\t\t\treturn m, nil\n\t\t}\n\n\tcase resultMsg:\n\t\tm.message = string(msg)\n\t\treturn m, tea.Quit\n\n\tcase stateMsg:\n\t\tm.state = state(msg)\n\t\treturn m, nil\n\n\tcase progress.Message:\n\t\treturn m, m.progress.SetPercent(float64(msg))\n\n\tcase progress_.FrameMsg:\n\t\treturn m, m.progress.Update(msg)\n\n\tdefault:\n\t\ts, cmd := m.spinner.Update(msg)\n\t\tm.spinner = &s\n\t\treturn m, cmd\n\t}\n}\n\nfunc (m *model) View() string {\n\tif len(m.message) > 0 {\n\t\treturn textStyle.Render(m.message)\n\t}\n\n\tvar message string\n\tm.spinner.Spinner = spinner.Dot\n\n\tswitch m.state {\n\tcase validating:\n\t\tmessage = \"Validating current installation\"\n\tcase downloading:\n\t\tmessage = fmt.Sprintf(\"Downloading %s from %s...\\n%s\", m.config.Latest, m.config.Source.String(), m.progress.View())\n\t\treturn textStyle.Render(message)\n\tcase verifying:\n\t\tm.spinner.Spinner = spinner.Moon\n\t\tmessage = \"Verifying download\"\n\tcase installing:\n\t\tm.spinner.Spinner = spinner.Jump\n\t\tmessage = \"Installing\"\n\t}\n\n\treturn textStyle.Render(fmt.Sprintf(\"%s %s\", m.spinner.View(), message))\n}\n\nfunc Run(cfg *Config) error {\n\tprogram = tea.NewProgram(initialModel(cfg))\n\tresultModel, _ := program.Run()\n\n\tprogramModel, OK := resultModel.(*model)\n\tif !OK {\n\t\tlog.Debug(\"failed to cast model\")\n\t\treturn nil\n\t}\n\n\treturn programModel.error\n}\n\nfunc IsMajorUpgrade(current, latest string) bool {\n\tif current == \"\" {\n\t\treturn false\n\t}\n\n\tgetMajorNumber := func(version string) string {\n\t\tmajor, _, _ := strings.Cut(version, \".\")\n\t\treturn major\n\t}\n\n\treturn getMajorNumber(current) != getMajorNumber(latest)\n}\n"
  },
  {
    "path": "src/cli/upgrade/tui_test.go",
    "content": "package upgrade\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestIsMajorUpgrade(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tCurrentVersion string\n\t\tLatestVersion  string\n\t\tExpected       bool\n\t}{\n\t\t{Case: \"Same version\", Expected: false, CurrentVersion: \"v3.0.0\", LatestVersion: \"v3.0.0\"},\n\t\t{Case: \"Breaking change\", Expected: true, CurrentVersion: \"v3.0.0\", LatestVersion: \"v4.0.0\"},\n\t\t{Case: \"Empty version, mostly development build\", Expected: false, LatestVersion: \"v4.0.0\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tcanUpgrade := IsMajorUpgrade(tc.CurrentVersion, tc.LatestVersion)\n\t\tassert.Equal(t, tc.Expected, canUpgrade, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/cli/upgrade/verify.go",
    "content": "package upgrade\n\nimport (\n\t\"crypto/ed25519\"\n\t\"crypto/sha256\"\n\t\"crypto/x509\"\n\t_ \"embed\"\n\t\"encoding/pem\"\n\t\"fmt\"\n\tstdruntime \"runtime\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\n// This is based on the following key generation and validation.\n// Generate a private key:\n// openssl genpkey -algorithm Ed25519 -out private_key.pem\n// Extract the public key:\n// openssl pkey -in private_key.pem -pubout -out public_key.pem\n// Sign the checksums.txt file:\n// openssl pkeyutl -sign -inkey private_key.pem -out checksums.txt.sig -rawin -in checksums.txt\n// Verify the signature:\n// openssl pkeyutl -verify -pubin -inkey public_key.pem -sigfile checksums.txt.sig -rawin -in checksums.txt\n// The public key is embedded in the binary.\n// The private key is used to sign the checksums.txt file.\n// The signature is embedded in the release.\n// The checksums.txt file contains the checksums of the release assets.\n// All checks are done in memory.\n// Only then the binary is written to disk.\n\n//go:embed public_key.pem\nvar publicKey []byte\n\nfunc downloadAndVerify(cfg *Config) ([]byte, error) {\n\textension := \"\"\n\tif stdruntime.GOOS == runtime.WINDOWS {\n\t\textension = \".exe\"\n\t}\n\n\tasset := fmt.Sprintf(\"posh-%s-%s%s\", stdruntime.GOOS, stdruntime.GOARCH, extension)\n\n\tlog.Debug(\"downloading asset:\", asset)\n\n\tdata, err := cfg.DownloadAsset(asset)\n\tif err != nil {\n\t\tlog.Debug(\"failed to download asset\")\n\t\treturn nil, err\n\t}\n\n\tsetState(verifying)\n\n\terr = verify(cfg, asset, data)\n\tif err != nil {\n\t\tlog.Debug(\"failed to verify asset\")\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n\nfunc verify(cfg *Config, asset string, binary []byte) error {\n\tchecksums, err := cfg.DownloadAsset(\"checksums.txt\")\n\tif err != nil {\n\t\tlog.Debug(\"failed to download checksums\")\n\t\treturn err\n\t}\n\n\tsignature, err := cfg.DownloadAsset(\"checksums.txt.sig\")\n\tif err != nil {\n\t\tlog.Debug(\"failed to download checksums signature\")\n\t\treturn err\n\t}\n\n\tOK := validateSignature(checksums, signature)\n\tif !OK {\n\t\tlog.Debug(\"failed to verify checksums signature\")\n\t\treturn fmt.Errorf(\"failed to verify checksums signature\")\n\t}\n\n\treturn validateChecksum(asset, checksums, binary)\n}\n\nfunc validateSignature(data, signature []byte) bool {\n\ted25519PublicKey, err := loadPublicKey()\n\tif err != nil {\n\t\tlog.Debug(\"failed to load public key\")\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn ed25519.Verify(*ed25519PublicKey, data, signature)\n}\n\nfunc loadPublicKey() (*ed25519.PublicKey, error) {\n\tblock, _ := pem.Decode(publicKey)\n\tif block == nil {\n\t\tlog.Debug(\"failed to decode PEM block\")\n\t\treturn nil, fmt.Errorf(\"error parsing PEM block: key not found\")\n\t}\n\n\tpubKey, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\tlog.Debug(\"failed to parse public key\")\n\t\treturn nil, fmt.Errorf(\"error parsing public key: %v\", err)\n\t}\n\n\ted25519PubKey, ok := pubKey.(ed25519.PublicKey)\n\tif !ok {\n\t\tlog.Debug(\"failed to convert public key to ed25519\")\n\t\treturn nil, fmt.Errorf(\"invalid public key format: %v\", err)\n\t}\n\n\treturn &ed25519PubKey, nil\n}\n\nfunc validateChecksum(asset string, sha256sums, binary []byte) error {\n\tvar assetChecksum string\n\tchecksums := strings.SplitSeq(string(sha256sums), \"\\n\")\n\n\tfor line := range checksums {\n\t\tif !strings.HasSuffix(line, asset) {\n\t\t\tcontinue\n\t\t}\n\n\t\tassetChecksum = strings.Fields(line)[0]\n\t\tbreak\n\t}\n\n\tif assetChecksum == \"\" {\n\t\tlog.Debug(\"failed to find checksum for asset\")\n\t\treturn fmt.Errorf(\"failed to find checksum for asset\")\n\t}\n\n\t// calculate the checksum of the binary\n\tbinaryChecksum := fmt.Sprintf(\"%x\", sha256.Sum256(binary))\n\n\tif assetChecksum != binaryChecksum {\n\t\tlog.Debugf(\"checksum mismatch, expected: %s, got: %s\", assetChecksum, binaryChecksum)\n\t\treturn fmt.Errorf(\"checksum mismatch\")\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/cli/upgrade/verify_test.go",
    "content": "package upgrade\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestVerify(t *testing.T) {\n\tchecksum, err := os.ReadFile(\"../../test/signing/checksums.txt\")\n\tassert.NoError(t, err)\n\n\tsignature, err := os.ReadFile(\"../../test/signing/checksums.txt.sig\")\n\tassert.NoError(t, err)\n\n\tOK := validateSignature(checksum, signature)\n\tassert.True(t, OK)\n}\n\nfunc TestVerifyFail(t *testing.T) {\n\tchecksum, err := os.ReadFile(\"../../test/signing/checksums.txt\")\n\tassert.NoError(t, err)\n\n\tsignature, err := os.ReadFile(\"../../test/signing/checksums.txt.invalid.sig\")\n\tassert.NoError(t, err)\n\n\tOK := validateSignature(checksum, signature)\n\tassert.False(t, OK)\n}\n"
  },
  {
    "path": "src/cli/upgrade.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\tstdruntime \"runtime\"\n\t\"slices\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tforce bool\n\tauto  bool\n)\n\n// upgradeCmd represents the upgrade command\nvar upgradeCmd = &cobra.Command{\n\tUse:   \"upgrade\",\n\tShort: \"Upgrade when a new version is available.\",\n\tLong:  \"Upgrade when a new version is available.\",\n\tArgs:  cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tvar startTime time.Time\n\n\t\tif debug {\n\t\t\tstartTime = time.Now()\n\t\t\tlog.Enable(plain)\n\t\t}\n\n\t\tif upgrade.IsPackagedInstallation() {\n\t\t\tmsg := \"upgrade is not supported when installed as a MSIX package\"\n\t\t\tlog.Debug(msg)\n\t\t\tfmt.Printf(\"\\n  ❌ %s\\n\\n\", msg)\n\t\t\treturn\n\t\t}\n\n\t\tsupportedPlatforms := []string{\n\t\t\truntime.WINDOWS,\n\t\t\truntime.DARWIN,\n\t\t\truntime.LINUX,\n\t\t}\n\n\t\tif !slices.Contains(supportedPlatforms, stdruntime.GOOS) {\n\t\t\tlog.Debug(\"unsupported platform\")\n\t\t\treturn\n\t\t}\n\n\t\tsh := os.Getenv(\"POSH_SHELL\")\n\n\t\tenv := &runtime.Terminal{}\n\t\tenv.Init(&runtime.Flags{\n\t\t\tDebug: debug,\n\t\t})\n\n\t\tcache.Init(sh, cache.Persist)\n\n\t\t// Only respect the cache interval when using --auto flag\n\t\tif _, OK := cache.Get[string](cache.Device, upgrade.CACHEKEY); OK && auto {\n\t\t\tlog.Debug(\"upgrade check already performed recently, skipping\")\n\t\t\treturn\n\t\t}\n\n\t\tterminal.Init(sh)\n\t\tfmt.Print(terminal.StartProgress())\n\n\t\tcfg := config.Get(configFlag, false)\n\n\t\tdefer func() {\n\t\t\tfmt.Print(terminal.StopProgress())\n\n\t\t\t// Set the cache key after any upgrade check to prevent redundant checks\n\t\t\tcache.Set(cache.Device, upgrade.CACHEKEY, \"true\", cfg.Upgrade.Interval)\n\n\t\t\tcache.Close()\n\n\t\t\tif !debug {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tsb := text.NewBuilder()\n\n\t\t\tsb.WriteString(fmt.Sprintf(\"%s %s\\n\", log.Text(\"Upgrade duration:\").Green().Bold().Plain(), time.Since(startTime)))\n\n\t\t\tsb.WriteString(log.Text(\"\\nLogs:\\n\\n\").Green().Bold().Plain().String())\n\t\t\tsb.WriteString(env.Logs())\n\n\t\t\tfmt.Println(sb.String())\n\t\t}()\n\n\t\tlatest, err := cfg.Upgrade.FetchLatest()\n\t\tif err != nil {\n\t\t\tlog.Debug(\"failed to get latest version\")\n\t\t\tlog.Error(err)\n\t\t\tfmt.Printf(\"\\n  ❌ %s\\n\\n\", err)\n\n\t\t\texitcode = 1\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debugf(\"current version: v%s, latest version: v%s\", build.Version, latest)\n\n\t\tif force {\n\t\t\tlog.Debug(\"forced upgrade\")\n\t\t\texitcode = executeUpgrade(cfg.Upgrade)\n\t\t\treturn\n\t\t}\n\n\t\tif upgrade.IsMajorUpgrade(build.Version, latest) {\n\t\t\tlog.Debug(\"major upgrade available\")\n\t\t\tmessage := fmt.Sprintf(\"\\n  🚨 major upgrade available: v%s -> v%s, use oh-my-posh upgrade --force to upgrade\\n\\n\", build.Version, latest)\n\t\t\tfmt.Print(message)\n\t\t\treturn\n\t\t}\n\n\t\tif build.Version != latest {\n\t\t\tlog.Debug(\"upgrade available\")\n\t\t\texitcode = executeUpgrade(cfg.Upgrade)\n\t\t\treturn\n\t\t}\n\n\t\tlog.Debug(\"already on the latest version\")\n\t},\n}\n\nfunc executeUpgrade(cfg *upgrade.Config) int {\n\terr := upgrade.Run(cfg)\n\tif err == nil {\n\t\treturn 0\n\t}\n\n\tlog.Debug(\"failed to upgrade\")\n\tlog.Error(err)\n\n\treturn 1\n}\n\nfunc init() {\n\tupgradeCmd.Flags().BoolVarP(&force, \"force\", \"f\", false, \"force the upgrade even if the version is up to date\")\n\tupgradeCmd.Flags().BoolVar(&auto, \"auto\", false, \"respect the cache interval for automatic upgrades\")\n\tupgradeCmd.Flags().BoolVar(&debug, \"debug\", false, \"enable/disable debug mode\")\n\tRootCmd.AddCommand(upgradeCmd)\n}\n"
  },
  {
    "path": "src/cli/version.go",
    "content": "package cli\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tverbose bool\n)\n\n// versionCmd represents the version command\nvar versionCmd = &cobra.Command{\n\tUse:   \"version\",\n\tShort: \"Print the version\",\n\tLong:  \"Print the version number of oh-my-posh.\",\n\tArgs:  cobra.NoArgs,\n\tRun: func(_ *cobra.Command, _ []string) {\n\t\tif !verbose {\n\t\t\tfmt.Println(build.Version)\n\t\t\treturn\n\t\t}\n\t\tfmt.Println(\"Version: \", build.Version)\n\t\tfmt.Println(\"Date:    \", build.Date)\n\t},\n}\n\nfunc init() {\n\tversionCmd.Flags().BoolVarP(&verbose, \"verbose\", \"v\", false, \"write verbose output\")\n\tRootCmd.AddCommand(versionCmd)\n}\n"
  },
  {
    "path": "src/color/colors.go",
    "content": "package color\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gookit/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n)\n\nfunc init() {\n\tgob.Register(&Set{})\n\tgob.Register((*Ansi)(nil))\n\tgob.Register(&Palette{})\n\tgob.Register(&Palettes{})\n\tgob.Register(&Cycle{})\n}\n\nconst (\n\taccentColor = \"accent_color\"\n)\n\nvar TrueColor = true\n\n// String is the interface that wraps ToColor method.\n//\n// ToColor gets the ANSI color code for a given color string.\n// This can include a valid hex color in the format `#FFFFFF`,\n// but also a name of one of the first 16 ANSI colors like `lightBlue`.\ntype String interface {\n\tToAnsi(colorString Ansi, isBackground bool) Ansi\n\tResolve(colorString Ansi) (Ansi, error)\n}\n\ntype Set struct {\n\tBackground Ansi `json:\"background\" toml:\"background\" yaml:\"background\"`\n\tForeground Ansi `json:\"foreground\" toml:\"foreground\" yaml:\"foreground\"`\n}\n\nfunc (c *Set) String() string {\n\treturn fmt.Sprintf(\"%s|%s\", c.Foreground, c.Background)\n}\n\nfunc (c *Set) ParseString(colors string) {\n\tparts := strings.SplitN(colors, \"|\", 3)\n\tif len(parts) != 2 {\n\t\treturn\n\t}\n\n\tc.Foreground = Ansi(parts[0])\n\tc.Background = Ansi(parts[1])\n}\n\ntype History []*Set\n\nfunc (c *History) Len() int {\n\treturn len(*c)\n}\n\nfunc (c *History) Add(background, foreground Ansi) {\n\tcolors := &Set{\n\t\tForeground: foreground,\n\t\tBackground: background,\n\t}\n\n\tif c.Len() == 0 {\n\t\t*c = append(*c, colors)\n\t\treturn\n\t}\n\n\tlast := (*c)[c.Len()-1]\n\t// never add the same colors twice\n\tif last.Foreground == colors.Foreground && last.Background == colors.Background {\n\t\treturn\n\t}\n\n\t*c = append(*c, colors)\n}\n\nfunc (c *History) Pop() {\n\tif c.Len() == 0 {\n\t\treturn\n\t}\n\n\t*c = (*c)[:c.Len()-1]\n}\n\nfunc (c *History) Background() Ansi {\n\tif c.Len() == 0 {\n\t\treturn emptyColor\n\t}\n\n\treturn (*c)[c.Len()-1].Background\n}\n\nfunc (c *History) Foreground() Ansi {\n\tif c.Len() == 0 {\n\t\treturn emptyColor\n\t}\n\n\treturn (*c)[c.Len()-1].Foreground\n}\n\n// Ansi is an ANSI color code ready to be printed to the console.\n// Example: \"38;2;255;255;255\", \"48;2;255;255;255\", \"31\", \"95\".\ntype Ansi string\n\nconst (\n\temptyColor = Ansi(\"\")\n)\n\nfunc (c Ansi) IsEmpty() bool {\n\treturn c == emptyColor\n}\n\nfunc (c Ansi) IsTransparent() bool {\n\treturn c == Transparent\n}\n\nfunc (c Ansi) IsClear() bool {\n\treturn c == Transparent || c == emptyColor\n}\n\nfunc (c Ansi) ToForeground() Ansi {\n\tcolorString := c.String()\n\tif strings.HasPrefix(colorString, \"38;\") {\n\t\treturn Ansi(strings.Replace(colorString, \"38;\", \"48;\", 1))\n\t}\n\treturn c\n}\n\nfunc (c Ansi) ResolveTemplate() Ansi {\n\tif c.IsEmpty() {\n\t\treturn c\n\t}\n\n\tif c.IsTransparent() {\n\t\treturn emptyColor\n\t}\n\n\ttext, err := template.Render(string(c), nil)\n\tif err != nil {\n\t\treturn Transparent\n\t}\n\n\treturn Ansi(text)\n}\n\nfunc (c Ansi) String() string {\n\treturn string(c)\n}\n\nfunc MakeColors(palette Palette, cacheEnabled bool, accentColor Ansi, env runtime.Environment) (colors String) {\n\tdefaultColors := &Defaults{}\n\tdefaultColors.SetAccentColor(env, accentColor)\n\tcolors = defaultColors\n\n\tif palette != nil {\n\t\tcolors = &PaletteColors{ansiColors: colors, palette: palette}\n\t}\n\n\tif cacheEnabled {\n\t\tcolors = &Cached{ansiColors: colors}\n\t}\n\n\treturn\n}\n\nfunc (d *Defaults) SetAccentColor(env runtime.Environment, defaultColor Ansi) {\n\tdefer log.Trace(time.Now())\n\n\t// get accent color from session cache first\n\tif accent, OK := cache.Get[*Set](cache.Device, accentColor); OK {\n\t\td.accent = accent\n\t\treturn\n\t}\n\n\trgb, err := GetAccentColor(env)\n\tif err != nil {\n\t\td.accent = &Set{\n\t\t\tForeground: d.ToAnsi(defaultColor, false),\n\t\t\tBackground: d.ToAnsi(defaultColor, true),\n\t\t}\n\n\t\treturn\n\t}\n\n\tif defaultColor == \"\" {\n\t\treturn\n\t}\n\n\tforeground := color.RGB(rgb.R, rgb.G, rgb.B, false)\n\tbackground := color.RGB(rgb.R, rgb.G, rgb.B, true)\n\n\td.accent = &Set{\n\t\tForeground: Ansi(foreground.String()),\n\t\tBackground: Ansi(background.String()),\n\t}\n\n\tcache.Set(cache.Device, accentColor, d.accent, cache.INFINITE)\n}\n\ntype RGB struct {\n\tR, G, B uint8\n}\n\n// Defaults is the default AnsiColors implementation.\ntype Defaults struct {\n\taccent *Set\n}\n\nvar (\n\t// Map for color names and their respective foreground [0] or background [1] color codes\n\tansiColorCodes = map[Ansi][2]Ansi{\n\t\t\"black\":        {\"30\", \"40\"},\n\t\t\"red\":          {\"31\", \"41\"},\n\t\t\"green\":        {\"32\", \"42\"},\n\t\t\"yellow\":       {\"33\", \"43\"},\n\t\t\"blue\":         {\"34\", \"44\"},\n\t\t\"magenta\":      {\"35\", \"45\"},\n\t\t\"cyan\":         {\"36\", \"46\"},\n\t\t\"white\":        {\"37\", \"47\"},\n\t\t\"default\":      {\"39\", \"49\"},\n\t\t\"darkGray\":     {\"90\", \"100\"},\n\t\t\"lightRed\":     {\"91\", \"101\"},\n\t\t\"lightGreen\":   {\"92\", \"102\"},\n\t\t\"lightYellow\":  {\"93\", \"103\"},\n\t\t\"lightBlue\":    {\"94\", \"104\"},\n\t\t\"lightMagenta\": {\"95\", \"105\"},\n\t\t\"lightCyan\":    {\"96\", \"106\"},\n\t\t\"lightWhite\":   {\"97\", \"107\"},\n\t}\n)\n\nfunc (d *Defaults) ToAnsi(ansiColor Ansi, isBackground bool) Ansi {\n\tif ansiColor == \"\" {\n\t\treturn emptyColor\n\t}\n\n\tif ansiColor.IsTransparent() {\n\t\treturn ansiColor\n\t}\n\n\tif ansiColor == Accent {\n\t\tif d.accent == nil {\n\t\t\treturn emptyColor\n\t\t}\n\n\t\tif isBackground {\n\t\t\treturn d.accent.Background\n\t\t}\n\n\t\treturn d.accent.Foreground\n\t}\n\n\tcolorFromName, err := getAnsiColorFromName(ansiColor, isBackground)\n\tif err == nil {\n\t\treturn colorFromName\n\t}\n\n\tcolorString := ansiColor.String()\n\n\tif !strings.HasPrefix(colorString, \"#\") {\n\t\tval, err := strconv.ParseUint(colorString, 10, 64)\n\t\tif err != nil || val > 255 {\n\t\t\treturn emptyColor\n\t\t}\n\n\t\tc256 := color.C256(uint8(val), isBackground)\n\t\treturn Ansi(c256.String())\n\t}\n\n\tstyle := color.HEX(colorString, isBackground)\n\tif !style.IsEmpty() {\n\t\tif TrueColor {\n\t\t\treturn Ansi(style.String())\n\t\t}\n\n\t\treturn Ansi(style.C256().String())\n\t}\n\n\tif colorInt, err := strconv.ParseInt(colorString, 10, 8); err == nil {\n\t\tc := color.C256(uint8(colorInt), isBackground)\n\n\t\treturn Ansi(c.String())\n\t}\n\n\treturn emptyColor\n}\n\nfunc (d *Defaults) Resolve(colorString Ansi) (Ansi, error) {\n\treturn colorString, nil\n}\n\n// getAnsiColorFromName returns the color code for a given color name if the name is\n// known ANSI color name.\nfunc getAnsiColorFromName(colorValue Ansi, isBackground bool) (Ansi, error) {\n\tif colorCodes, found := ansiColorCodes[colorValue]; found {\n\t\treturn colorCodes[generics.ToInt[int](isBackground)], nil\n\t}\n\n\treturn \"\", fmt.Errorf(\"color name %s does not exist\", colorValue)\n}\n\nfunc IsAnsiColorName(colorValue Ansi) bool {\n\t_, ok := ansiColorCodes[colorValue]\n\treturn ok\n}\n\n// PaletteColors is the AnsiColors Decorator that uses the Palette to do named color\n// lookups before ANSI color code generation.\ntype PaletteColors struct {\n\tansiColors String\n\tpalette    Palette\n}\n\nfunc (p *PaletteColors) ToAnsi(colorString Ansi, isBackground bool) Ansi {\n\tpaletteColor, err := p.palette.ResolveColor(colorString)\n\tif err != nil {\n\t\treturn emptyColor\n\t}\n\n\tansiColor := p.ansiColors.ToAnsi(paletteColor, isBackground)\n\n\treturn ansiColor\n}\n\nfunc (p *PaletteColors) Resolve(colorString Ansi) (Ansi, error) {\n\treturn p.palette.ResolveColor(colorString)\n}\n\n// Cached is the AnsiColors Decorator that does simple color lookup caching.\n// ToColor calls are cheap, but not free, and having a simple cache in\n// has measurable positive effect on performance.\ntype Cached struct {\n\tansiColors String\n\tcolorCache map[cachedColorKey]Ansi\n}\n\ntype cachedColorKey struct {\n\tcolorString  Ansi\n\tisBackground bool\n}\n\nfunc (c *Cached) ToAnsi(colorString Ansi, isBackground bool) Ansi {\n\tif c.colorCache == nil {\n\t\tc.colorCache = make(map[cachedColorKey]Ansi)\n\t}\n\n\tkey := cachedColorKey{colorString, isBackground}\n\tif ansiColor, hit := c.colorCache[key]; hit {\n\t\treturn ansiColor\n\t}\n\n\tansiColor := c.ansiColors.ToAnsi(colorString, isBackground)\n\tc.colorCache[key] = ansiColor\n\treturn ansiColor\n}\n\nfunc (c *Cached) Resolve(colorString Ansi) (Ansi, error) {\n\treturn c.ansiColors.Resolve(colorString)\n}\n"
  },
  {
    "path": "src/color/colors_darwin.go",
    "content": "package color\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nfunc GetAccentColor(env runtime.Environment) (*RGB, error) {\n\toutput, err := env.RunCommand(\"defaults\", \"read\", \"-g\", \"AppleAccentColor\")\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, errors.New(\"unable to read accent color\")\n\t}\n\n\tindex, err := strconv.Atoi(output)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, errors.New(\"unable to parse accent color index\")\n\t}\n\n\tvar accentColors = map[int]RGB{\n\t\t-1: {152, 152, 152}, // Graphite\n\t\t0:  {224, 55, 62},   // Red\n\t\t1:  {247, 130, 25},  // Orange\n\t\t2:  {255, 199, 38},  // Yellow\n\t\t3:  {96, 186, 70},   // Green\n\t\t4:  {0, 122, 255},   // Blue\n\t\t5:  {149, 61, 150},  // Purple\n\t\t6:  {247, 79, 159},  // Pink\n\t}\n\n\tcolor, exists := accentColors[index]\n\tif !exists {\n\t\tcolor = accentColors[6] // Default to graphite (white)\n\t}\n\n\treturn &color, nil\n}\n"
  },
  {
    "path": "src/color/colors_test.go",
    "content": "package color\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n)\n\nfunc TestGetAnsiFromColorString(t *testing.T) {\n\tcases := []struct {\n\t\tCase       string\n\t\tExpected   Ansi\n\t\tColor      Ansi\n\t\tBackground bool\n\t\tColor256   bool\n\t}{\n\t\t{Case: \"256 color\", Expected: Ansi(\"38;5;99\"), Color: \"99\", Background: false},\n\t\t{Case: \"256 color\", Expected: Ansi(\"38;5;122\"), Color: \"122\", Background: false},\n\t\t{Case: \"Invalid background\", Expected: emptyColor, Color: \"invalid\", Background: true},\n\t\t{Case: \"Invalid background\", Expected: emptyColor, Color: \"invalid\", Background: false},\n\t\t{Case: \"Hex foreground\", Expected: Ansi(\"38;2;170;187;204\"), Color: \"#AABBCC\", Background: false},\n\t\t{Case: \"Hex background\", Expected: Ansi(\"48;2;170;187;204\"), Color: \"#AABBCC\", Background: true},\n\t\t{Case: \"Base 8 foreground\", Expected: Ansi(\"31\"), Color: \"red\", Background: false},\n\t\t{Case: \"Base 8 background\", Expected: Ansi(\"41\"), Color: \"red\", Background: true},\n\t\t{Case: \"Base 16 foreground\", Expected: Ansi(\"91\"), Color: \"lightRed\", Background: false},\n\t\t{Case: \"Base 16 background\", Expected: Ansi(\"101\"), Color: \"lightRed\", Background: true},\n\t\t{Case: \"Non true color TERM\", Expected: Ansi(\"38;5;146\"), Color: \"#AABBCC\", Color256: true},\n\t}\n\tfor _, tc := range cases {\n\t\tansiColors := &Defaults{}\n\t\tTrueColor = !tc.Color256\n\t\tansiColor := ansiColors.ToAnsi(tc.Color, tc.Background)\n\t\tassert.Equal(t, tc.Expected, ansiColor, tc.Case)\n\t}\n}\n\nfunc TestMakeColors(t *testing.T) {\n\tenv := &mock.Environment{}\n\n\tcache.Set(cache.Device, accentColor, &Set{}, cache.INFINITE)\n\tdefer cache.DeleteAll(cache.Device)\n\n\tenv.On(\"WindowsRegistryKeyValue\", `HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\DWM\\ColorizationColor`).Return(&runtime.WindowsRegistryValue{}, errors.New(\"err\"))\n\tcolors := MakeColors(nil, false, \"\", env)\n\tassert.IsType(t, &Defaults{}, colors)\n\n\tcolors = MakeColors(nil, true, \"\", env)\n\tassert.IsType(t, &Cached{}, colors)\n\tassert.IsType(t, &Defaults{}, colors.(*Cached).ansiColors)\n\n\tcolors = MakeColors(testPalette, false, \"\", env)\n\tassert.IsType(t, &PaletteColors{}, colors)\n\tassert.IsType(t, &Defaults{}, colors.(*PaletteColors).ansiColors)\n\n\tcolors = MakeColors(testPalette, true, \"\", env)\n\tassert.IsType(t, &Cached{}, colors)\n\tassert.IsType(t, &PaletteColors{}, colors.(*Cached).ansiColors)\n\tassert.IsType(t, &Defaults{}, colors.(*Cached).ansiColors.(*PaletteColors).ansiColors)\n}\n\nfunc TestAnsiRender(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected Ansi\n\t\tTerm     string\n\t}{\n\t\t{Case: \"Inside vscode\", Expected: \"#123456\", Term: \"vscode\"},\n\t\t{Case: \"Outside vscode\", Expected: \"\", Term: \"windowsterminal\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"TERM_PROGRAM\").Return(tc.Term)\n\t\tenv.On(\"Shell\").Return(\"foo\")\n\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tansi := Ansi(\"{{ if eq \\\"vscode\\\" .Env.TERM_PROGRAM }}#123456{{end}}\")\n\t\tgot := ansi.ResolveTemplate()\n\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/color/colors_unix.go",
    "content": "//go:build !windows && !darwin\n\npackage color\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\nfunc GetAccentColor(_ runtime.Environment) (*RGB, error) {\n\treturn nil, &runtime.NotImplemented{}\n}\n"
  },
  {
    "path": "src/color/colors_windows.go",
    "content": "package color\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nfunc GetAccentColor(env runtime.Environment) (*RGB, error) {\n\tdefer log.Trace(time.Now())\n\n\tif env == nil {\n\t\treturn nil, errors.New(\"unable to get color without environment\")\n\t}\n\n\t// see https://stackoverflow.com/questions/3560890/vista-7-how-to-get-glass-color\n\tvalue, err := env.WindowsRegistryKeyValue(`HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\DWM\\ColorizationColor`)\n\tif err != nil || value.ValueType != runtime.DWORD {\n\t\treturn nil, err\n\t}\n\n\treturn &RGB{\n\t\tR: byte(value.DWord >> 16),\n\t\tG: byte(value.DWord >> 8),\n\t\tB: byte(value.DWord),\n\t}, nil\n}\n"
  },
  {
    "path": "src/color/cycle.go",
    "content": "package color\n\ntype Cycle []*Set\n\nfunc (c Cycle) Loop() (*Set, Cycle) {\n\tif len(c) == 0 {\n\t\treturn nil, c\n\t}\n\n\treturn c[0], append(c[1:], c[0])\n}\n"
  },
  {
    "path": "src/color/keywords.go",
    "content": "package color\n\nconst (\n\t// Transparent implies a transparent color\n\tTransparent Ansi = \"transparent\"\n\t// Accent is the OS accent color\n\tAccent Ansi = \"accent\"\n\t// ParentBackground takes the previous segment's background color\n\tParentBackground Ansi = \"parentBackground\"\n\t// ParentForeground takes the previous segment's color\n\tParentForeground Ansi = \"parentForeground\"\n\t// Background takes the current segment's background color\n\tBackground Ansi = \"background\"\n\t// Foreground takes the current segment's foreground color\n\tForeground Ansi = \"foreground\"\n)\n\nfunc (color Ansi) isKeyword() bool {\n\tswitch color { //nolint: exhaustive\n\tcase Transparent, ParentBackground, ParentForeground, Background, Foreground:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (color Ansi) Resolve(current *Set, parents []*Set) Ansi {\n\tresolveParentColor := func(keyword Ansi) Ansi {\n\t\tfor _, parentColor := range parents {\n\t\t\tif parentColor == nil {\n\t\t\t\treturn Transparent\n\t\t\t}\n\n\t\t\tswitch keyword { //nolint: exhaustive\n\t\t\tcase ParentBackground:\n\t\t\t\tkeyword = parentColor.Background\n\t\t\tcase ParentForeground:\n\t\t\t\tkeyword = parentColor.Foreground\n\t\t\tdefault:\n\t\t\t\tif keyword == \"\" {\n\t\t\t\t\treturn Transparent\n\t\t\t\t}\n\t\t\t\treturn keyword\n\t\t\t}\n\t\t}\n\n\t\tif keyword == \"\" {\n\t\t\treturn Transparent\n\t\t}\n\n\t\treturn keyword\n\t}\n\n\tresolveKeyword := func(keyword Ansi) Ansi {\n\t\tswitch {\n\t\tcase keyword == Background && current != nil:\n\t\t\treturn current.Background\n\t\tcase keyword == Foreground && current != nil:\n\t\t\treturn current.Foreground\n\t\tcase (keyword == ParentBackground || keyword == ParentForeground) && parents != nil:\n\t\t\treturn resolveParentColor(keyword)\n\t\tdefault:\n\t\t\treturn Transparent\n\t\t}\n\t}\n\n\tfor color.isKeyword() {\n\t\tresolved := resolveKeyword(color)\n\t\tif resolved == color {\n\t\t\tbreak\n\t\t}\n\n\t\tcolor = resolved\n\t}\n\n\treturn color\n}\n"
  },
  {
    "path": "src/color/palette.go",
    "content": "package color\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\ntype Palette map[Ansi]Ansi\n\nconst (\n\tpaletteKeyPrefix         = \"p:\"\n\tpaletteKeyError          = \"palette: requested color %s does not exist in palette of colors %s\"\n\tpaletteMaxRecursionDepth = 3 // allows 3 or less recursive resolutions\n\tpaletteRecursiveKeyError = \"palette: recursive resolution of color %s returned palette reference %s and reached recursion depth %d\"\n)\n\n// ResolveColor gets a color value from the palette using given colorName.\n// If colorName is not a palette reference, it is returned as is.\nfunc (p Palette) ResolveColor(colorName Ansi) (Ansi, error) {\n\treturn p.resolveColor(colorName, 1, &colorName)\n}\n\n// originalColorName is a pointer to save allocations\nfunc (p Palette) resolveColor(colorName Ansi, depth int, originalColorName *Ansi) (Ansi, error) {\n\tkey, ok := asPaletteKey(colorName)\n\t// colorName is not a palette key, return it as is\n\tif !ok {\n\t\treturn colorName, nil\n\t}\n\n\tcolor, ok := p[key]\n\tif !ok {\n\t\treturn \"\", &PaletteKeyError{Key: key, palette: p}\n\t}\n\n\tif _, isKey := isPaletteKey(color); isKey {\n\t\tif depth > paletteMaxRecursionDepth {\n\t\t\treturn \"\", &PaletteRecursiveKeyError{Key: *originalColorName, Value: color, depth: depth}\n\t\t}\n\n\t\treturn p.resolveColor(color, depth+1, originalColorName)\n\t}\n\n\treturn color, nil\n}\n\nfunc asPaletteKey(colorName Ansi) (Ansi, bool) {\n\tprefix, isKey := isPaletteKey(colorName)\n\tif !isKey {\n\t\treturn \"\", false\n\t}\n\n\tkey := strings.TrimPrefix(colorName.String(), prefix.String())\n\n\treturn Ansi(key), true\n}\n\nfunc isPaletteKey(colorName Ansi) (Ansi, bool) {\n\treturn paletteKeyPrefix, strings.HasPrefix(colorName.String(), paletteKeyPrefix)\n}\n\n// PaletteKeyError records the missing Palette key.\ntype PaletteKeyError struct {\n\tpalette Palette\n\tKey     Ansi\n}\n\nfunc (p *PaletteKeyError) Error() string {\n\tkeys := make([]string, 0, len(p.palette))\n\tfor key := range p.palette {\n\t\tkeys = append(keys, key.String())\n\t}\n\tsort.Strings(keys)\n\tallColors := strings.Join(keys, \",\")\n\terrorStr := fmt.Sprintf(paletteKeyError, p.Key, allColors)\n\treturn errorStr\n}\n\n// PaletteRecursiveKeyError records the Palette key and resolved color value (which\n// is also a Palette key)\ntype PaletteRecursiveKeyError struct {\n\tKey   Ansi\n\tValue Ansi\n\tdepth int\n}\n\nfunc (p *PaletteRecursiveKeyError) Error() string {\n\terrorStr := fmt.Sprintf(paletteRecursiveKeyError, p.Key, p.Value, p.depth)\n\treturn errorStr\n}\n\n// MaybeResolveColor wraps resolveColor and silences possible errors, returning\n// Transparent color by default, as a Block does not know how to handle color errors.\nfunc (p Palette) MaybeResolveColor(colorName Ansi) Ansi {\n\tcolor, err := p.ResolveColor(colorName)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn color\n}\n"
  },
  {
    "path": "src/color/palette_test.go",
    "content": "package color\n\nimport (\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nvar (\n\ttestPalette = Palette{\n\t\t\"red\":   \"#FF0000\",\n\t\t\"green\": \"#00FF00\",\n\t\t\"blue\":  \"#0000FF\",\n\t\t\"white\": \"#FFFFFF\",\n\t\t\"black\": \"#000000\",\n\t}\n)\n\ntype TestPaletteRequest struct {\n\tCase          string\n\tRequest       Ansi\n\tExpected      Ansi\n\tExpectedError bool\n}\n\nfunc TestPaletteShouldResolveColorFromTestPalette(t *testing.T) {\n\tcases := []TestPaletteRequest{\n\t\t{Case: \"Palette red\", Request: \"p:red\", Expected: \"#FF0000\"},\n\t\t{Case: \"Palette green\", Request: \"p:green\", Expected: \"#00FF00\"},\n\t\t{Case: \"Palette blue\", Request: \"p:blue\", Expected: \"#0000FF\"},\n\t\t{Case: \"Palette white\", Request: \"p:white\", Expected: \"#FFFFFF\"},\n\t\t{Case: \"Palette black\", Request: \"p:black\", Expected: \"#000000\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttestPaletteRequest(t, tc)\n\t}\n}\n\nfunc testPaletteRequest(t *testing.T, tc TestPaletteRequest) {\n\tactual, err := testPalette.ResolveColor(tc.Request)\n\n\tif !tc.ExpectedError {\n\t\tassert.Nil(t, err, tc.Case)\n\t\tassert.Equal(t, tc.Expected, actual, \"expected different color value\")\n\t} else {\n\t\tassert.NotNil(t, err, tc.Case)\n\t\tassert.Equal(t, string(tc.Expected), err.Error())\n\t}\n}\n\nfunc TestPaletteShouldIgnoreNonPaletteColors(t *testing.T) {\n\tcases := []TestPaletteRequest{\n\t\t{Case: \"Deep puprple\", Request: \"#1F1137\", Expected: \"#1F1137\"},\n\t\t{Case: \"Light red\", Request: \"#D55252\", Expected: \"#D55252\"},\n\t\t{Case: \"ANSI black\", Request: \"black\", Expected: \"black\"},\n\t\t{Case: \"Foreground\", Request: \"foreground\", Expected: \"foreground\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttestPaletteRequest(t, tc)\n\t}\n}\n\nfunc TestPaletteShouldReturnErrorOnMissingColor(t *testing.T) {\n\tcases := []TestPaletteRequest{\n\t\t{\n\t\t\tCase:          \"Palette deep purple\",\n\t\t\tRequest:       \"p:deep-purple\",\n\t\t\tExpectedError: true,\n\t\t\tExpected:      \"palette: requested color deep-purple does not exist in palette of colors black,blue,green,red,white\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Palette cyan\",\n\t\t\tRequest:       \"p:cyan\",\n\t\t\tExpectedError: true,\n\t\t\tExpected:      \"palette: requested color cyan does not exist in palette of colors black,blue,green,red,white\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Palette foreground\",\n\t\t\tRequest:       \"p:foreground\",\n\t\t\tExpectedError: true,\n\t\t\tExpected:      \"palette: requested color foreground does not exist in palette of colors black,blue,green,red,white\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttestPaletteRequest(t, tc)\n\t}\n}\n\nfunc TestPaletteShouldHandleMixedCases(t *testing.T) {\n\tcases := []TestPaletteRequest{\n\t\t{Case: \"Palette red\", Request: \"p:red\", Expected: \"#FF0000\"},\n\t\t{Case: \"ANSI black\", Request: \"black\", Expected: \"black\"},\n\t\t{Case: \"Cyan\", Request: \"#05E6FA\", Expected: \"#05E6FA\"},\n\t\t{Case: \"Palette black\", Request: \"p:black\", Expected: \"#000000\"},\n\t\t{Case: \"Palette pink\", Request: \"p:pink\", ExpectedError: true, Expected: \"palette: requested color pink does not exist in palette of colors black,blue,green,red,white\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttestPaletteRequest(t, tc)\n\t}\n}\n\nfunc TestPaletteShouldUseEmptyColorByDefault(t *testing.T) {\n\tcases := []TestPaletteRequest{\n\t\t{Case: \"Palette magenta\", Request: \"p:magenta\", Expected: \"\"},\n\t\t{Case: \"Palette gray\", Request: \"p:gray\", Expected: \"\"},\n\t\t{Case: \"Palette rose\", Request: \"p:rose\", Expected: \"\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tactual := testPalette.MaybeResolveColor(tc.Request)\n\n\t\tassert.Equal(t, tc.Expected, actual, \"expected different color value\")\n\t}\n}\n\nfunc TestPaletteShouldResolveRecursiveReference(t *testing.T) {\n\ttp := Palette{\n\t\t\"light-blue\": \"#CAF0F8\",\n\t\t\"dark-blue\":  \"#023E8A\",\n\t\t\"foreground\": \"p:light-blue\",\n\t\t\"background\": \"p:dark-blue\",\n\t\t\"text\":       \"p:foreground\",\n\t\t\"icon\":       \"p:background\",\n\t\t\"void\":       \"p:void\", // infinite recursion - error\n\t\t\"1\":          \"white\",\n\t\t\"2\":          \"p:1\",\n\t\t\"3\":          \"p:2\",\n\t\t\"4\":          \"p:3\", // 3 recursive lookups - allowed\n\t\t\"5\":          \"p:4\", // 4 recursive lookups - error\n\t}\n\n\tcases := []TestPaletteRequest{\n\t\t{\n\t\t\tCase:     \"Palette light-blue\",\n\t\t\tRequest:  \"p:light-blue\",\n\t\t\tExpected: \"#CAF0F8\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Palette foreground\",\n\t\t\tRequest:  \"p:foreground\",\n\t\t\tExpected: \"#CAF0F8\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Palette background\",\n\t\t\tRequest:  \"p:background\",\n\t\t\tExpected: \"#023E8A\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Palette text (2 recursive lookups)\",\n\t\t\tRequest:  \"p:text\",\n\t\t\tExpected: \"#CAF0F8\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Palette icon (2 recursive lookups)\",\n\t\t\tRequest:  \"p:icon\",\n\t\t\tExpected: \"#023E8A\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Palette void (infinite recursion)\",\n\t\t\tRequest:       \"p:void\",\n\t\t\tExpectedError: true,\n\t\t\tExpected:      \"palette: recursive resolution of color p:void returned palette reference p:void and reached recursion depth 4\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Palette p:4 (3 recursive lookups)\",\n\t\t\tRequest:  \"p:4\",\n\t\t\tExpected: \"white\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Palette p:5 (4 recursive lookups)\",\n\t\t\tRequest:       \"p:5\",\n\t\t\tExpectedError: true,\n\t\t\tExpected:      \"palette: recursive resolution of color p:5 returned palette reference p:1 and reached recursion depth 4\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tactual, err := tp.ResolveColor(tc.Request)\n\n\t\tif !tc.ExpectedError {\n\t\t\tassert.Nil(t, err, \"expected no error\")\n\t\t\tassert.Equal(t, tc.Expected, actual, \"expected different color value\")\n\t\t} else {\n\t\t\tassert.NotNil(t, err, \"expected error\")\n\t\t\tassert.Equal(t, string(tc.Expected), err.Error())\n\t\t}\n\t}\n}\n\nfunc TestPaletteShouldHandleEmptyKey(t *testing.T) {\n\ttp := Palette{\n\t\t\"\": \"#000000\",\n\t}\n\n\tactual, err := tp.ResolveColor(\"p:\")\n\n\tassert.Nil(t, err, \"expected no error\")\n\tassert.Equal(t, Ansi(\"#000000\"), actual, \"expected different color value\")\n}\n\nfunc BenchmarkPaletteMixedCaseResolution(b *testing.B) {\n\tfor b.Loop() {\n\t\tbenchmarkPaletteMixedCaseResolution()\n\t}\n}\n\nfunc benchmarkPaletteMixedCaseResolution() {\n\tcases := []TestPaletteRequest{\n\t\t{Case: \"Palette red\", Request: \"p:red\", Expected: \"#FF0000\"},\n\t\t{Case: \"ANSI black\", Request: \"black\", Expected: \"black\"},\n\t\t{Case: \"Cyan\", Request: \"#05E6FA\", Expected: \"#05E6FA\"},\n\t\t{Case: \"Palette black\", Request: \"p:black\", Expected: \"#000000\"},\n\t\t{Case: \"Palette pink\", Request: \"p:pink\", ExpectedError: true, Expected: \"palette: requested color pink does not exist in palette of colors black,blue,green,red,white\"},\n\t\t{Case: \"Palette blue\", Request: \"p:blue\", Expected: \"#0000FF\"},\n\t\t// repeating the same set to have longer benchmarks\n\t\t{Case: \"Palette red\", Request: \"p:red\", Expected: \"#FF0000\"},\n\t\t{Case: \"ANSI black\", Request: \"black\", Expected: \"black\"},\n\t\t{Case: \"Cyan\", Request: \"#05E6FA\", Expected: \"#05E6FA\"},\n\t\t{Case: \"Palette black\", Request: \"p:black\", Expected: \"#000000\"},\n\t\t{Case: \"Palette pink\", Request: \"p:pink\", ExpectedError: true, Expected: \"palette: requested color pink does not exist in palette of colors black,blue,green,red,white\"},\n\t\t{Case: \"Palette blue\", Request: \"p:blue\", Expected: \"#0000FF\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\t// both value and error values are irrelevant, but such assignment calms down\n\t\t// golangci-lint \"return value of `testPalette.ResolveColor` is not checked\" error\n\t\t_, _ = testPalette.ResolveColor(tc.Request)\n\t}\n}\n"
  },
  {
    "path": "src/color/palettes.go",
    "content": "package color\n\ntype Palettes struct {\n\tList     map[string]Palette `json:\"list,omitempty\" toml:\"list,omitempty\" yaml:\"list,omitempty\"`\n\tTemplate string             `json:\"template,omitempty\" toml:\"template,omitempty\" yaml:\"template,omitempty\"`\n}\n"
  },
  {
    "path": "src/config/backup.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\ttoml \"github.com/pelletier/go-toml/v2\"\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\nfunc (cfg *Config) Backup() {\n\tdst := cfg.Source + \".bak\"\n\tsource, err := os.Open(cfg.Source)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer source.Close()\n\tdestination, err := os.Create(dst)\n\tif err != nil {\n\t\treturn\n\t}\n\tdefer destination.Close()\n\t_, err = io.Copy(destination, source)\n\tif err != nil {\n\t\treturn\n\t}\n}\n\nfunc (cfg *Config) Export(format string) string {\n\tif len(format) != 0 {\n\t\tcfg.Format = format\n\t}\n\n\tvar result bytes.Buffer\n\n\tswitch cfg.Format {\n\tcase YAML:\n\t\tprefix := \"# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\\n\\n\"\n\t\tyamlEncoder := yaml.NewEncoder(&result)\n\n\t\terr := yamlEncoder.Encode(cfg)\n\t\tif err != nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn prefix + result.String()\n\tcase JSON:\n\t\tjsonEncoder := json.NewEncoder(&result)\n\t\tjsonEncoder.SetEscapeHTML(false)\n\t\tjsonEncoder.SetIndent(\"\", \"  \")\n\t\t_ = jsonEncoder.Encode(cfg)\n\t\tprefix := \"{\\n  \\\"$schema\\\": \\\"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\\\",\"\n\t\tdata := strings.Replace(result.String(), \"{\", prefix, 1)\n\t\treturn EscapeGlyphs(data, cfg.MigrateGlyphs)\n\tcase TOML:\n\t\ttomlEncoder := toml.NewEncoder(&result)\n\t\ttomlEncoder.SetIndentTables(true)\n\n\t\terr := tomlEncoder.Encode(cfg)\n\t\tif err != nil {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn result.String()\n\t}\n\n\t// unsupported format\n\treturn \"\"\n}\n\nfunc (cfg *Config) Write(format string) {\n\tcontent := cfg.Export(format)\n\tif content == \"\" {\n\t\t// we are unable to perform the export\n\t\treturn\n\t}\n\n\tf, err := os.OpenFile(cfg.Source, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\t_ = f.Close()\n\t}()\n\n\t_, err = f.WriteString(content)\n\tif err != nil {\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "src/config/block.go",
    "content": "package config\n\nimport \"fmt\"\n\n// BlockType type of block\ntype BlockType string\n\n// BlockAlignment alignment of a Block\ntype BlockAlignment string\n\n// Overflow defines how to handle a right block that overflows with the previous block\ntype Overflow string\n\nconst (\n\t// Prompt writes one or more Segments\n\tPrompt BlockType = \"prompt\"\n\t// RPrompt is a right aligned prompt\n\tRPrompt BlockType = \"rprompt\"\n\t// Left aligns left\n\tLeft BlockAlignment = \"left\"\n\t// Right aligns right\n\tRight BlockAlignment = \"right\"\n\t// Break adds a line break\n\tBreak Overflow = \"break\"\n\t// Hide hides the block\n\tHide Overflow = \"hide\"\n)\n\n// Block defines a part of the prompt with optional segments\ntype Block struct {\n\tType            BlockType      `json:\"type,omitempty\" toml:\"type,omitempty\" yaml:\"type,omitempty\"`\n\tAlignment       BlockAlignment `json:\"alignment,omitempty\" toml:\"alignment,omitempty\" yaml:\"alignment,omitempty\"`\n\tFiller          string         `json:\"filler,omitempty\" toml:\"filler,omitempty\" yaml:\"filler,omitempty\"`\n\tOverflow        Overflow       `json:\"overflow,omitempty\" toml:\"overflow,omitempty\" yaml:\"overflow,omitempty\"`\n\tLeadingDiamond  string         `json:\"leading_diamond,omitempty\" toml:\"leading_diamond,omitempty\" yaml:\"leading_diamond,omitempty\"`\n\tTrailingDiamond string         `json:\"trailing_diamond,omitempty\" toml:\"trailing_diamond,omitempty\" yaml:\"trailing_diamond,omitempty\"`\n\tSegments        []*Segment     `json:\"segments,omitempty\" toml:\"segments,omitempty\" yaml:\"segments,omitempty\"`\n\tNewline         bool           `json:\"newline,omitempty\" toml:\"newline,omitempty\" yaml:\"newline,omitempty\"`\n\tForce           bool           `json:\"force,omitempty\" toml:\"force,omitempty\" yaml:\"force,omitempty\"`\n\tIndex           int            `json:\"index,omitempty\" toml:\"index,omitempty\" yaml:\"index,omitempty\"`\n}\n\nfunc (b *Block) key() any {\n\tif b.Index > 0 {\n\t\treturn b.Index - 1\n\t}\n\n\treturn fmt.Sprintf(\"%s-%s\", b.Type, b.Alignment)\n}\n"
  },
  {
    "path": "src/config/cache.go",
    "content": "package config\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\ntype Cache struct {\n\tDuration cache.Duration `json:\"duration,omitempty\" toml:\"duration,omitempty\" yaml:\"duration,omitempty\"`\n\tStrategy Strategy       `json:\"strategy,omitempty\" toml:\"strategy,omitempty\" yaml:\"strategy,omitempty\"`\n}\n\ntype Strategy string\n\nconst (\n\tFolder  Strategy = \"folder\"\n\tSession Strategy = \"session\"\n\tDevice  Strategy = \"device\"\n)\n"
  },
  {
    "path": "src/config/config.go",
    "content": "package config\n\nimport (\n\t\"encoding/gob\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\nfunc init() {\n\tgob.Register(&Config{})\n}\n\nconst (\n\tJSON string = \"json\"\n\tYAML string = \"yaml\"\n\tTOML string = \"toml\"\n\n\tTML   string = \"tml\"\n\tYML   string = \"yml\"\n\tJSONC string = \"jsonc\"\n\n\tAUTOUPGRADE   = \"upgrade\"\n\tUPGRADENOTICE = \"notice\"\n\tRELOAD        = \"reload\"\n\n\tVersion = 4\n)\n\ntype Action string\n\nfunc (a Action) IsDefault() bool {\n\treturn a != Prepend && a != Extend\n}\n\nconst (\n\tPrepend Action = \"prepend\"\n\tExtend  Action = \"extend\"\n)\n\n// Config holds all the theme for rendering the prompt\ntype Config struct {\n\tPalette                 color.Palette          `json:\"palette,omitempty\" toml:\"palette,omitempty\" yaml:\"palette,omitempty\"`\n\tDebugPrompt             *Segment               `json:\"debug_prompt,omitempty\" toml:\"debug_prompt,omitempty\" yaml:\"debug_prompt,omitempty\"`\n\tVar                     map[string]any         `json:\"var,omitempty\" toml:\"var,omitempty\" yaml:\"var,omitempty\"`\n\tPalettes                *color.Palettes        `json:\"palettes,omitempty\" toml:\"palettes,omitempty\" yaml:\"palettes,omitempty\"`\n\tValidLine               *Segment               `json:\"valid_line,omitempty\" toml:\"valid_line,omitempty\" yaml:\"valid_line,omitempty\"`\n\tSecondaryPrompt         *Segment               `json:\"secondary_prompt,omitempty\" toml:\"secondary_prompt,omitempty\" yaml:\"secondary_prompt,omitempty\"`\n\tTransientPrompt         *Segment               `json:\"transient_prompt,omitempty\" toml:\"transient_prompt,omitempty\" yaml:\"transient_prompt,omitempty\"`\n\tErrorLine               *Segment               `json:\"error_line,omitempty\" toml:\"error_line,omitempty\" yaml:\"error_line,omitempty\"`\n\tMaps                    *maps.Config           `json:\"maps,omitempty\" toml:\"maps,omitempty\" yaml:\"maps,omitempty\"`\n\tUpgrade                 *upgrade.Config        `json:\"upgrade,omitempty\" toml:\"upgrade,omitempty\" yaml:\"upgrade,omitempty\"`\n\tExtends                 string                 `json:\"extends,omitempty\" toml:\"extends,omitempty\" yaml:\"extends,omitempty\"`\n\tAccentColor             color.Ansi             `json:\"accent_color,omitempty\" toml:\"accent_color,omitempty\" yaml:\"accent_color,omitempty\"`\n\tConsoleTitleTemplate    string                 `json:\"console_title_template,omitempty\" toml:\"console_title_template,omitempty\" yaml:\"console_title_template,omitempty\"`\n\tPWD                     string                 `json:\"pwd,omitempty\" toml:\"pwd,omitempty\" yaml:\"pwd,omitempty\"`\n\tSource                  string                 `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tFormat                  string                 `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tTerminalBackground      color.Ansi             `json:\"terminal_background,omitempty\" toml:\"terminal_background,omitempty\" yaml:\"terminal_background,omitempty\"`\n\tToolTipsAction          Action                 `json:\"tooltips_action,omitempty\" toml:\"tooltips_action,omitempty\" yaml:\"tooltips_action,omitempty\"`\n\tBlocks                  []*Block               `json:\"blocks,omitempty\" toml:\"blocks,omitempty\" yaml:\"blocks,omitempty\"`\n\tCycle                   color.Cycle            `json:\"cycle,omitempty\" toml:\"cycle,omitempty\" yaml:\"cycle,omitempty\"`\n\tITermFeatures           terminal.ITermFeatures `json:\"iterm_features,omitempty\" toml:\"iterm_features,omitempty\" yaml:\"iterm_features,omitempty\"`\n\tTooltips                []*Segment             `json:\"tooltips,omitempty\" toml:\"tooltips,omitempty\" yaml:\"tooltips,omitempty\"`\n\thash                    uint64\n\tVersion                 int  `json:\"version\" toml:\"version\" yaml:\"version\"`\n\tMigrateGlyphs           bool `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tAsync                   bool `json:\"async,omitempty\" toml:\"async,omitempty\" yaml:\"async,omitempty\"`\n\tShellIntegration        bool `json:\"shell_integration,omitempty\" toml:\"shell_integration,omitempty\" yaml:\"shell_integration,omitempty\"`\n\tFinalSpace              bool `json:\"final_space,omitempty\" toml:\"final_space,omitempty\" yaml:\"final_space,omitempty\"`\n\tUpgradeNotice           bool `json:\"-\" toml:\"-\" yaml:\"-\"`\n\textended                bool\n\tPatchPwshBleed          bool `json:\"patch_pwsh_bleed,omitempty\" toml:\"patch_pwsh_bleed,omitempty\" yaml:\"patch_pwsh_bleed,omitempty\"`\n\tAutoUpgrade             bool `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tEnableCursorPositioning bool `json:\"enable_cursor_positioning,omitempty\" toml:\"enable_cursor_positioning,omitempty\" yaml:\"enable_cursor_positioning,omitempty\"`\n\tStreaming               int  `json:\"streaming,omitempty\" toml:\"streaming,omitempty\" yaml:\"streaming,omitempty\"`\n}\n\nfunc (cfg *Config) MakeColors(env runtime.Environment) color.String {\n\tcacheDisabled := env.Getenv(\"OMP_CACHE_DISABLED\") == \"1\"\n\treturn color.MakeColors(cfg.getPalette(), !cacheDisabled, cfg.AccentColor, env)\n}\n\nfunc (cfg *Config) getPalette() color.Palette {\n\tif cfg.Palettes == nil {\n\t\treturn cfg.Palette\n\t}\n\n\tkey, err := template.Render(cfg.Palettes.Template, nil)\n\tif err != nil {\n\t\treturn cfg.Palette\n\t}\n\n\tpalette, ok := cfg.Palettes.List[key]\n\tif !ok {\n\t\treturn cfg.Palette\n\t}\n\n\tfor key, color := range cfg.Palette {\n\t\tif _, ok := palette[key]; ok {\n\t\t\tcontinue\n\t\t}\n\n\t\tpalette[key] = color\n\t}\n\n\treturn palette\n}\n\nfunc (cfg *Config) Features(env runtime.Environment) shell.Features {\n\tvar feats shell.Features\n\n\tasyncShells := []string{shell.BASH, shell.ZSH, shell.FISH, shell.PWSH}\n\n\tif cfg.Async && slices.Contains(asyncShells, env.Shell()) {\n\t\tlog.Debug(\"async enabled\")\n\t\tfeats |= shell.Async\n\t}\n\n\tif cfg.TransientPrompt != nil {\n\t\tlog.Debug(\"transient prompt enabled\")\n\t\tfeats |= shell.Transient\n\t}\n\n\tif cfg.Streaming > 0 {\n\t\tlog.Debug(\"streaming enabled\")\n\t\tfeats |= shell.Streaming\n\t}\n\n\tif feats&(shell.Streaming|shell.Transient) != 0 {\n\t\tfeats |= shell.KeyHandlers\n\t}\n\n\tunsupportedShells := []string{shell.ELVISH, shell.XONSH}\n\tif slices.Contains(unsupportedShells, env.Shell()) {\n\t\tcfg.ShellIntegration = false\n\t}\n\n\tif cfg.ShellIntegration {\n\t\tlog.Debug(\"shell integration enabled\")\n\t\tfeats |= shell.FTCSMarks\n\t}\n\n\t// do not enable upgrade features when async is enabled\n\tif feats&shell.Async == 0 {\n\t\tfeats |= cfg.upgradeFeatures()\n\t}\n\n\tif cfg.ErrorLine != nil || cfg.ValidLine != nil {\n\t\tlog.Debug(\"error or valid line enabled\")\n\t\tfeats |= shell.LineError\n\t}\n\n\tif len(cfg.Tooltips) > 0 {\n\t\tlog.Debug(\"tooltips enabled\")\n\t\tfeats |= shell.Tooltips\n\t}\n\n\tif env.Shell() == shell.FISH && cfg.ITermFeatures != nil && cfg.ITermFeatures.Contains(terminal.PromptMark) {\n\t\tlog.Debug(\"prompt mark enabled\")\n\t\tfeats |= shell.PromptMark\n\t}\n\n\tfor i, block := range cfg.Blocks {\n\t\tif (i == 0 && block.Newline) && cfg.EnableCursorPositioning {\n\t\t\tlog.Debug(\"cursor positioning enabled\")\n\t\t\tfeats |= shell.CursorPositioning\n\t\t}\n\n\t\tif block.Type == RPrompt {\n\t\t\tlog.Debug(\"rprompt enabled\")\n\t\t\tfeats |= shell.RPrompt\n\t\t}\n\n\t\tfor _, segment := range block.Segments {\n\t\t\tif segment.Type == AZ {\n\t\t\t\tsource := segment.Options.String(segments.Source, segments.FirstMatch)\n\t\t\t\tif strings.Contains(source, segments.Pwsh) {\n\t\t\t\t\tlog.Debug(\"azure enabled\")\n\t\t\t\t\tfeats |= shell.Azure\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif segment.Type == GIT {\n\t\t\t\tsource := segment.Options.String(segments.Source, segments.Cli)\n\t\t\t\tif source == segments.Pwsh {\n\t\t\t\t\tlog.Debug(\"posh-git enabled\")\n\t\t\t\t\tfeats |= shell.PoshGit\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn feats\n}\n\nfunc (cfg *Config) upgradeFeatures() shell.Features {\n\tvar feats shell.Features\n\n\tautoUpgrade := cfg.Upgrade.Auto\n\tif val, OK := cache.Get[bool](cache.Device, AUTOUPGRADE); OK {\n\t\tlog.Debug(\"auto upgrade key found, overriding config\")\n\t\tautoUpgrade = val\n\t}\n\n\tupgradeNotice := cfg.Upgrade.DisplayNotice\n\tif val, OK := cache.Get[bool](cache.Device, UPGRADENOTICE); OK {\n\t\tlog.Debug(\"upgrade notice key found, overriding config\")\n\t\tupgradeNotice = val\n\t}\n\n\tif upgradeNotice && !autoUpgrade {\n\t\tlog.Debug(\"notice enabled, no auto upgrade\")\n\t\tfeats |= shell.Notice\n\t}\n\n\tif autoUpgrade {\n\t\tlog.Debug(\"auto upgrade enabled\")\n\t\tfeats |= shell.Upgrade\n\t}\n\n\treturn feats\n}\n\nfunc (cfg *Config) Hash() uint64 {\n\treturn cfg.hash\n}\n\n// migrateSegmentProperties migrates the deprecated Properties field to Options for all segments.\n// This is needed for TOML configs since go-toml/v2 doesn't support custom unmarshalers.\nfunc (cfg *Config) migrateSegmentProperties() {\n\tfor _, block := range cfg.Blocks {\n\t\tfor _, segment := range block.Segments {\n\t\t\tsegment.MigratePropertiesToOptions()\n\t\t}\n\t}\n}\n\n// toggleSegments processes all segments in all blocks and adds segments\n// with Toggled == true to the toggle cache, effectively toggling them off.\nfunc (cfg *Config) toggleSegments() {\n\tcurrentToggleSet, _ := cache.Get[map[string]bool](cache.Session, cache.TOGGLECACHE)\n\tif currentToggleSet == nil {\n\t\tcurrentToggleSet = make(map[string]bool)\n\t}\n\n\tfor _, block := range cfg.Blocks {\n\t\tfor _, segment := range block.Segments {\n\t\t\tif segment.Toggled {\n\t\t\t\tsegmentName := segment.Alias\n\t\t\t\tif segmentName == \"\" {\n\t\t\t\t\tsegmentName = string(segment.Type)\n\t\t\t\t}\n\n\t\t\t\tcurrentToggleSet[segmentName] = true\n\t\t\t}\n\t\t}\n\t}\n\n\t// Update cache with the map directly\n\tcache.Set(cache.Session, cache.TOGGLECACHE, currentToggleSet, cache.INFINITE)\n}\n"
  },
  {
    "path": "src/config/config_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetPalette(t *testing.T) {\n\tpalette := color.Palette{\n\t\t\"red\":  \"#ff0000\",\n\t\t\"blue\": \"#0000ff\",\n\t}\n\n\tcases := []struct {\n\t\tPalettes        *color.Palettes\n\t\tPalette         color.Palette\n\t\tExpectedPalette color.Palette\n\t\tCase            string\n\t}{\n\t\t{\n\t\t\tCase: \"match\",\n\t\t\tPalettes: &color.Palettes{\n\t\t\t\tTemplate: \"{{ .Shell }}\",\n\t\t\t\tList: map[string]color.Palette{\n\t\t\t\t\t\"bash\": palette,\n\t\t\t\t\t\"zsh\": {\n\t\t\t\t\t\t\"red\":  \"#ff0001\",\n\t\t\t\t\t\t\"blue\": \"#0000fb\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tExpectedPalette: palette,\n\t\t},\n\t\t{\n\t\t\tCase: \"no match, no fallback\",\n\t\t\tPalettes: &color.Palettes{\n\t\t\t\tTemplate: \"{{ .Shell }}\",\n\t\t\t\tList: map[string]color.Palette{\n\t\t\t\t\t\"fish\": palette,\n\t\t\t\t\t\"zsh\": {\n\t\t\t\t\t\t\"red\":  \"#ff0001\",\n\t\t\t\t\t\t\"blue\": \"#0000fb\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tExpectedPalette: nil,\n\t\t},\n\t\t{\n\t\t\tCase: \"no match, default\",\n\t\t\tPalettes: &color.Palettes{\n\t\t\t\tTemplate: \"{{ .Shell }}\",\n\t\t\t\tList: map[string]color.Palette{\n\t\t\t\t\t\"zsh\": {\n\t\t\t\t\t\t\"red\":  \"#ff0001\",\n\t\t\t\t\t\t\"blue\": \"#0000fb\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tPalette:         palette,\n\t\t\tExpectedPalette: palette,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no palettes\",\n\t\t\tExpectedPalette: nil,\n\t\t},\n\t\t{\n\t\t\tCase: \"match, with override\",\n\t\t\tPalettes: &color.Palettes{\n\t\t\t\tTemplate: \"{{ .Shell }}\",\n\t\t\t\tList: map[string]color.Palette{\n\t\t\t\t\t\"bash\": {\n\t\t\t\t\t\t\"red\":    \"#ff0001\",\n\t\t\t\t\t\t\"yellow\": \"#ffff00\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tPalette: palette,\n\t\t\tExpectedPalette: color.Palette{\n\t\t\t\t\"red\":    \"#ff0001\",\n\t\t\t\t\"blue\":   \"#0000ff\",\n\t\t\t\t\"yellow\": \"#ffff00\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tenv.On(\"Shell\").Return(\"bash\")\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell: \"bash\",\n\t\t\t},\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tcfg := &Config{\n\t\t\tPalette:  tc.Palette,\n\t\t\tPalettes: tc.Palettes,\n\t\t}\n\n\t\tgot := cfg.getPalette()\n\t\tassert.Equal(t, tc.ExpectedPalette, got, tc.Case)\n\t}\n}\nfunc TestUpgradeFeatures(t *testing.T) {\n\tcases := []struct {\n\t\tCase                  string\n\t\tExpectedFeats         shell.Features\n\t\tUpgradeCacheKeyExists bool\n\t\tAutoUpgrade           bool\n\t\tForce                 bool\n\t\tDisplayNotice         bool\n\t\tAutoUpgradeKey        bool\n\t\tNoticeKey             bool\n\t}{\n\t\t{\n\t\t\tCase:                  \"cache exists, no force\",\n\t\t\tUpgradeCacheKeyExists: true,\n\t\t\tExpectedFeats:         0,\n\t\t},\n\t\t{\n\t\t\tCase:          \"auto upgrade enabled\",\n\t\t\tAutoUpgrade:   true,\n\t\t\tExpectedFeats: shell.Upgrade,\n\t\t},\n\t\t{\n\t\t\tCase:           \"auto upgrade via cache\",\n\t\t\tAutoUpgradeKey: true,\n\t\t\tExpectedFeats:  shell.Upgrade,\n\t\t},\n\t\t{\n\t\t\tCase:          \"notice enabled, no auto upgrade\",\n\t\t\tDisplayNotice: true,\n\t\t\tExpectedFeats: shell.Notice,\n\t\t},\n\t\t{\n\t\t\tCase:          \"notice via cache, no auto upgrade\",\n\t\t\tNoticeKey:     true,\n\t\t\tExpectedFeats: shell.Notice,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"force upgrade ignores cache\",\n\t\t\tUpgradeCacheKeyExists: true,\n\t\t\tForce:                 true,\n\t\t\tAutoUpgrade:           true,\n\t\t\tExpectedFeats:         shell.Upgrade,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tif tc.UpgradeCacheKeyExists {\n\t\t\tcache.Set(cache.Device, upgrade.CACHEKEY, \"\", cache.INFINITE)\n\t\t}\n\n\t\tif tc.AutoUpgradeKey {\n\t\t\tcache.Set(cache.Device, AUTOUPGRADE, true, cache.INFINITE)\n\t\t}\n\n\t\tif tc.NoticeKey {\n\t\t\tcache.Set(cache.Device, UPGRADENOTICE, true, cache.INFINITE)\n\t\t}\n\n\t\tcfg := &Config{\n\t\t\tUpgrade: &upgrade.Config{\n\t\t\t\tAuto:          tc.AutoUpgrade,\n\t\t\t\tForce:         tc.Force,\n\t\t\t\tDisplayNotice: tc.DisplayNotice,\n\t\t\t},\n\t\t}\n\n\t\tgot := cfg.upgradeFeatures()\n\t\tassert.Equal(t, tc.ExpectedFeats, got, tc.Case)\n\n\t\tcache.DeleteAll(cache.Device)\n\t}\n}\n"
  },
  {
    "path": "src/config/default.go",
    "content": "package config\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nfunc Default(configError error) *Config {\n\texitBackgroundTemplate := \"{{ if gt .Code 0 }}p:red{{ end }}\"\n\texitTemplate := \" {{ if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} \"\n\n\tif configError != nil && configError != ErrNoConfig {\n\t\texitBackgroundTemplate = \"p:red\"\n\t\texitTemplate = configError.Error()\n\t}\n\n\tcfg := &Config{\n\t\thash:       1234567890, // placeholder hash value\n\t\tVersion:    4,\n\t\tFinalSpace: true,\n\t\tBlocks: []*Block{\n\t\t\t{\n\t\t\t\tType:      Prompt,\n\t\t\t\tAlignment: Left,\n\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            SESSION,\n\t\t\t\t\t\tStyle:           Diamond,\n\t\t\t\t\t\tLeadingDiamond:  \"\\ue0b6\",\n\t\t\t\t\t\tTrailingDiamond: \"\\ue0b0\",\n\t\t\t\t\t\tForeground:      \"p:black\",\n\t\t\t\t\t\tBackground:      \"p:yellow\",\n\t\t\t\t\t\tTemplate:        \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }} \",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            PATH,\n\t\t\t\t\t\tStyle:           Powerline,\n\t\t\t\t\t\tPowerlineSymbol: \"\\ue0b0\",\n\t\t\t\t\t\tForeground:      \"p:white\",\n\t\t\t\t\t\tBackground:      \"p:orange\",\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\toptions.Style: \"folder\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTemplate: \" \\uea83 {{ path .Path .Location }} \",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            GIT,\n\t\t\t\t\t\tStyle:           Powerline,\n\t\t\t\t\t\tPowerlineSymbol: \"\\ue0b0\",\n\t\t\t\t\t\tForeground:      \"p:black\",\n\t\t\t\t\t\tBackground:      \"p:green\",\n\t\t\t\t\t\tBackgroundTemplates: []string{\n\t\t\t\t\t\t\t\"{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if gt .Ahead 0 }}#49416D{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if gt .Behind 0 }}#7A306C{{ end }}\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tForegroundTemplates: []string{\n\t\t\t\t\t\t\t\"{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if gt .Ahead 0 }}p:white{{ end }}\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\tsegments.BranchTemplate:    \"{{ trunc 25 .Branch }}\",\n\t\t\t\t\t\t\tsegments.FetchStatus:       true,\n\t\t\t\t\t\t\tsegments.FetchUpstreamIcon: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTemplate: \" {{ if .UpstreamURL }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \", //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            ROOT,\n\t\t\t\t\t\tStyle:           Powerline,\n\t\t\t\t\t\tPowerlineSymbol: \"\\ue0b0\",\n\t\t\t\t\t\tForeground:      \"p:white\",\n\t\t\t\t\t\tBackground:      \"p:yellow\",\n\t\t\t\t\t\tTemplate:        \" \\uf0e7 \",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            STATUS,\n\t\t\t\t\t\tStyle:           Diamond,\n\t\t\t\t\t\tLeadingDiamond:  \"<transparent,background>\\ue0b0</>\",\n\t\t\t\t\t\tTrailingDiamond: \"\\ue0b4\",\n\t\t\t\t\t\tForeground:      \"p:white\",\n\t\t\t\t\t\tBackground:      \"p:blue\",\n\t\t\t\t\t\tBackgroundTemplates: []string{\n\t\t\t\t\t\t\texitBackgroundTemplate,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\toptions.AlwaysEnabled: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTemplate: exitTemplate,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType: RPrompt,\n\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:       NODE,\n\t\t\t\t\t\tStyle:      Plain,\n\t\t\t\t\t\tForeground: \"p:green\",\n\t\t\t\t\t\tBackground: \"transparent\",\n\t\t\t\t\t\tTemplate:   \"\\ue718 \",\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\tsegments.HomeEnabled:         false,\n\t\t\t\t\t\t\tsegments.FetchPackageManager: false,\n\t\t\t\t\t\t\tsegments.DisplayMode:         \"files\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:       GOLANG,\n\t\t\t\t\t\tStyle:      Plain,\n\t\t\t\t\t\tForeground: \"p:blue\",\n\t\t\t\t\t\tBackground: \"transparent\",\n\t\t\t\t\t\tTemplate:   \"\\ue626 \",\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\toptions.FetchVersion: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:       PYTHON,\n\t\t\t\t\t\tStyle:      Plain,\n\t\t\t\t\t\tForeground: \"p:yellow\",\n\t\t\t\t\t\tBackground: \"transparent\",\n\t\t\t\t\t\tTemplate:   \"\\ue235 \",\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\toptions.FetchVersion:     false,\n\t\t\t\t\t\t\tsegments.DisplayMode:     \"files\",\n\t\t\t\t\t\t\tsegments.FetchVirtualEnv: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:       SHELL,\n\t\t\t\t\t\tStyle:      Plain,\n\t\t\t\t\t\tForeground: \"p:white\",\n\t\t\t\t\t\tBackground: \"transparent\",\n\t\t\t\t\t\tTemplate:   \"in <p:blue><b>{{ .Name }}</b></> \",\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:       TIME,\n\t\t\t\t\t\tStyle:      Plain,\n\t\t\t\t\t\tForeground: \"p:white\",\n\t\t\t\t\t\tBackground: \"transparent\",\n\t\t\t\t\t\tTemplate:   \"at <p:blue><b>{{ .CurrentDate | date \\\"15:04:05\\\" }}</b></>\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tConsoleTitleTemplate: \"{{ .Shell }} in {{ .Folder }}\",\n\t\tPalette: color.Palette{\n\t\t\t\"black\":  \"#262B44\",\n\t\t\t\"blue\":   \"#4B95E9\",\n\t\t\t\"green\":  \"#59C9A5\",\n\t\t\t\"orange\": \"#F07623\",\n\t\t\t\"red\":    \"#D81E5B\",\n\t\t\t\"white\":  \"#E0DEF4\",\n\t\t\t\"yellow\": \"#F3AE35\",\n\t\t},\n\t\tSecondaryPrompt: &Segment{\n\t\t\tForeground: \"p:black\",\n\t\t\tBackground: \"transparent\",\n\t\t\tTemplate:   \"<p:yellow,transparent>\\ue0b6</><,p:yellow> > </><p:yellow,transparent>\\ue0b0</> \",\n\t\t},\n\t\tTransientPrompt: &Segment{\n\t\t\tForeground: \"p:black\",\n\t\t\tBackground: \"transparent\",\n\t\t\tTemplate:   \"<p:yellow,transparent>\\ue0b6</><,p:yellow> {{ .Folder }} </><p:yellow,transparent>\\ue0b0</> \",\n\t\t},\n\t\tTooltips: []*Segment{\n\t\t\t{\n\t\t\t\tType:            AWS,\n\t\t\t\tStyle:           Diamond,\n\t\t\t\tLeadingDiamond:  \"\\ue0b0\",\n\t\t\t\tTrailingDiamond: \"\\ue0b4\",\n\t\t\t\tForeground:      \"p:white\",\n\t\t\t\tBackground:      \"p:orange\",\n\t\t\t\tTemplate:        \" \\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n\t\t\t\tOptions: options.Map{\n\t\t\t\t\toptions.DisplayDefault: true,\n\t\t\t\t},\n\t\t\t\tTips: []string{\"aws\"},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:            AZ,\n\t\t\t\tStyle:           Diamond,\n\t\t\t\tLeadingDiamond:  \"\\ue0b0\",\n\t\t\t\tTrailingDiamond: \"\\ue0b4\",\n\t\t\t\tForeground:      \"p:white\",\n\t\t\t\tBackground:      \"p:blue\",\n\t\t\t\tTemplate:        \" \\uebd8 {{ .Name }} \",\n\t\t\t\tOptions: options.Map{\n\t\t\t\t\toptions.DisplayDefault: true,\n\t\t\t\t},\n\t\t\t\tTips: []string{\"az\"},\n\t\t\t},\n\t\t},\n\t\tUpgrade: &upgrade.Config{\n\t\t\tSource:   upgrade.CDN,\n\t\t\tInterval: cache.ONEWEEK,\n\t\t},\n\t}\n\n\treturn cfg\n}\n\nfunc Claude() *Config {\n\tcfg := &Config{\n\t\thash:    1234567890, // placeholder hash value\n\t\tVersion: 4,\n\t\tBlocks: []*Block{\n\t\t\t{\n\t\t\t\tType:      Prompt,\n\t\t\t\tAlignment: Left,\n\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:           PATH,\n\t\t\t\t\t\tStyle:          Diamond,\n\t\t\t\t\t\tLeadingDiamond: \"\\ue0b6\",\n\t\t\t\t\t\tForeground:     \"p:white\",\n\t\t\t\t\t\tBackground:     \"p:orange\",\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\tsegments.DirLength:           3,\n\t\t\t\t\t\t\tsegments.FolderSeparatorIcon: \"\\ue0bb\",\n\t\t\t\t\t\t\toptions.Style:                \"fish\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTemplate: \"{{ if .Segments.Git.Dir }} \\uf1d2 <i><b>{{ .Segments.Git.RepoName }}{{ if .Segments.Git.IsWorkTree }} \\ue21c{{ end }}</b></i>{{ $rel :=  .Segments.Git.RelativeDir }}{{ if $rel }} \\ueaf7 {{ .Format $rel }}{{ end }}{{ else }} \\uea83 {{ path .Path .Location }}{{ end }} \", //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            GIT,\n\t\t\t\t\t\tStyle:           Diamond,\n\t\t\t\t\t\tLeadingDiamond:  \"<parentBackground,background>\\ue0b0</>\",\n\t\t\t\t\t\tTrailingDiamond: \"\\ue0b4\",\n\t\t\t\t\t\tForeground:      \"p:black\",\n\t\t\t\t\t\tBackground:      \"p:green\",\n\t\t\t\t\t\tBackgroundTemplates: []string{\n\t\t\t\t\t\t\t\"{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if gt .Ahead 0 }}#49416D{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if gt .Behind 0 }}#7A306C{{ end }}\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tForegroundTemplates: []string{\n\t\t\t\t\t\t\t\"{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}\",\n\t\t\t\t\t\t\t\"{{ if or (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tOptions: options.Map{\n\t\t\t\t\t\t\tsegments.FetchStatus:       true,\n\t\t\t\t\t\t\tsegments.FetchUpstreamIcon: false,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tTemplate: \" {{ if .UpstreamURL }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ nospace .Working.String }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \", //nolint:lll\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:      Prompt,\n\t\t\t\tAlignment: Right,\n\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t{\n\t\t\t\t\t\tType:            CLAUDE,\n\t\t\t\t\t\tStyle:           Diamond,\n\t\t\t\t\t\tLeadingDiamond:  \"\\ue0b6\",\n\t\t\t\t\t\tTrailingDiamond: \"\\ue0b4\",\n\t\t\t\t\t\tForeground:      \"p:black\",\n\t\t\t\t\t\tBackground:      \"p:blue\",\n\t\t\t\t\t\tTemplate:        \" \\U000f0bc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.Gauge }} \",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tPalette: color.Palette{\n\t\t\t\"black\":  \"#262B44\",\n\t\t\t\"blue\":   \"#4B95E9\",\n\t\t\t\"green\":  \"#59C9A5\",\n\t\t\t\"orange\": \"#F07623\",\n\t\t\t\"red\":    \"#D81E5B\",\n\t\t\t\"white\":  \"#E0DEF4\",\n\t\t\t\"yellow\": \"#F3AE35\",\n\t\t},\n\t}\n\n\treturn cfg\n}\n"
  },
  {
    "path": "src/config/dsc.go",
    "content": "package config\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\nfunc init() {\n\tgob.Register([]*Configuration{})\n}\n\ntype Resource struct {\n\tdsc.Resource[*Configuration]\n}\n\nfunc DSC() *Resource {\n\treturn &Resource{\n\t\tResource: dsc.Resource[*Configuration]{},\n\t}\n}\n\ntype Configuration struct {\n\tFormat string `json:\"format,omitempty\" jsonschema:\"title=Format,description=The format of the configuration file,enum=json,enum=jsonc,enum=yaml,enum=yml,enum=toml,enum=tml\"`\n\tSource string `json:\"source,omitempty\" jsonschema:\"title=Source,description=The source of the configuration file\"`\n\tConfig\n\tresolved bool `json:\"-\"`\n}\n\nfunc (s *Resource) Add(configPath string) {\n\tif configPath == \"\" || strings.HasPrefix(configPath, \"http\") {\n\t\tlog.Debug(\"local configuration not provided or remote configuration, skipping\")\n\t\treturn\n\t}\n\n\t// replace $HOME with tilde as we can't guarantee the home path\n\tconfigPath = filepath.Clean(configPath)\n\tconfigPath = strings.ReplaceAll(configPath, path.Home(), \"~\")\n\n\ts.Resource.Add(&Configuration{\n\t\tSource: configPath,\n\t})\n}\n\nfunc (s *Resource) ToJSON() string {\n\toutput := s.Resource.ToJSON()\n\treturn EscapeGlyphs(output, false)\n}\n\nfunc (c *Configuration) Apply() error {\n\tif c == nil {\n\t\treturn nil\n\t}\n\n\tformats := map[string][]string{\n\t\tJSON: {\".json\", \".jsonc\"},\n\t\tYAML: {\".yaml\", \".yml\"},\n\t\tTOML: {\".toml\", \".tml\"},\n\t}\n\n\tif !slices.Contains(formats[c.Format], filepath.Ext(c.Source)) {\n\t\treturn fmt.Errorf(\"source file %s does not match format %s\", c.Source, c.Format)\n\t}\n\n\tlog.Debug(\"Applying configuration %s\", c.Source)\n\n\t// Expand tilde to home directory for file operations\n\tfilePath := strings.ReplaceAll(c.Source, \"~\", path.Home())\n\n\t// Create directory if it doesn't exist\n\tdir := filepath.Dir(filePath)\n\tif err := os.MkdirAll(dir, 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create directory %s: %w\", dir, err)\n\t}\n\n\tdata := c.Export(c.Format)\n\n\t// Write file\n\tif err := os.WriteFile(filePath, []byte(data), 0644); err != nil {\n\t\treturn fmt.Errorf(\"failed to write configuration file %s: %w\", filePath, err)\n\t}\n\n\tlog.Debug(\"Configuration written to %s\", filePath)\n\treturn nil\n}\n\nfunc (c *Configuration) Equal(config *Configuration) bool {\n\tif config == nil {\n\t\treturn false\n\t}\n\n\treturn c.Source == config.Source\n}\n\nfunc (c *Configuration) Resolve() (*Configuration, bool) {\n\tlog.Debug(\"Resolving configuration %s\", c.Source)\n\n\tif c.resolved {\n\t\tlog.Debug(\"Configuration already resolved\")\n\t\treturn c, true\n\t}\n\n\tc.resolved = true\n\n\t// we use pwsh as that will never omit any feature\n\tdata := Load(c.Source)\n\tif data == nil {\n\t\tlog.Debug(\"No configuration data found\")\n\t\treturn nil, false\n\t}\n\n\tc.Config = *data\n\tc.Format = data.Format\n\n\t// Skip if no extends, http URL\n\tif data.Extends == \"\" || strings.HasPrefix(data.Extends, \"http\") {\n\t\tlog.Debug(\"No extends found or remote configuration\")\n\t\treturn c, false\n\t}\n\n\t// Resolve the extends configuration\n\tparent := &Configuration{\n\t\tSource: data.Extends,\n\t}\n\n\treturn parent, true\n}\n"
  },
  {
    "path": "src/config/gob.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"encoding/base64\"\n\t\"encoding/gob\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nconst (\n\tconfigKey = \"CONFIG\"\n\tSourceKey = \"CONFIG_SOURCE\"\n)\n\nfunc (cfg *Config) Store() {\n\tdefer log.Trace(time.Now())\n\n\tcache.Set(cache.Session, SourceKey, cfg.Source, cache.INFINITE)\n\tcache.Set(cache.Session, configKey, cfg.Base64(), cache.INFINITE)\n}\n\nfunc Get(configFile string, reload bool) *Config {\n\tdefer log.Trace(time.Now())\n\n\tif reload {\n\t\tlog.Debug(\"reload mode enabled\")\n\t\tif source, OK := cache.Get[string](cache.Session, SourceKey); OK {\n\t\t\tcfg := Load(source)\n\t\t\tcfg.Store()\n\t\t\treturn cfg\n\t\t}\n\t}\n\n\tbase64String, found := cache.Get[string](cache.Session, configKey)\n\tif !found {\n\t\tlog.Debug(\"no cached config found\")\n\t\treturn Load(configFile)\n\t}\n\n\tvar cfg Config\n\tif err := cfg.Restore(base64String); err != nil {\n\t\tlog.Debug(\"failed to restore config from cache\")\n\t\treturn Load(configFile)\n\t}\n\n\treturn &cfg\n}\n\nfunc (cfg *Config) Base64() string {\n\tdefer log.Trace(time.Now())\n\n\tvar buffer bytes.Buffer\n\tencoder := gob.NewEncoder(&buffer)\n\terr := encoder.Encode(cfg)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\"\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(buffer.Bytes())\n}\n\nfunc (cfg *Config) Restore(base64String string) error {\n\tdefer log.Trace(time.Now())\n\n\tdata, err := base64.StdEncoding.DecodeString(base64String)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn err\n\t}\n\n\tvar buffer bytes.Buffer\n\tbuffer.Write(data)\n\tdecoder := gob.NewDecoder(&buffer)\n\terr = decoder.Decode(cfg)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/config/load.go",
    "content": "package config\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"os\"\n\t\"path/filepath\"\n\truntimelib \"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gookit/goutil/jsonutil\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\n\ttoml \"github.com/pelletier/go-toml/v2\"\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\n// Custom error types for config validation\ntype Error struct {\n\tmessage string\n}\n\nfunc (e Error) Error() string {\n\treturn fmt.Sprintf(\" %s \", e.message)\n}\n\nvar (\n\tErrFileNotFound     = Error{\"CONFIG NOT FOUND\"}\n\tErrInvalidExtension = Error{\"INVALID CONFIG EXTENSION\"}\n\tErrInvalidTheme     = Error{\"INVALID CONFIG THEME\"}\n\tErrURLFetch         = Error{\"CONFIG URL FETCH FAILED\"}\n\tErrParse            = Error{\"CONFIG PARSE ERROR\"}\n\tErrNoConfig         = Error{\"NO CONFIG\"}\n)\n\nfunc Load(configFile string) *Config {\n\tdefer log.Trace(time.Now())\n\n\tcfg, err := Parse(configFile)\n\tif err != nil {\n\t\tcfg = Default(err)\n\t}\n\n\treturn cfg\n}\n\nfunc resolveConfigLocation(config string) string {\n\tdefer log.Trace(time.Now())\n\n\tif strings.HasPrefix(config, \"https://\") {\n\t\treturn config\n\t}\n\n\tif url, OK := isTheme(config); OK {\n\t\tlog.Debug(\"theme detected, using theme file\")\n\t\treturn url\n\t}\n\n\t// Clean the config path so it works regardless of the OS\n\tconfig = filepath.ToSlash(config)\n\n\t// Cygwin path always needs the full path as we're on Windows but not really.\n\t// Doing filepath actions will convert it to a Windows path and break the init script.\n\tif isCygwin() {\n\t\tlog.Debug(\"cygwin detected, using full path for config\")\n\t\treturn config\n\t}\n\n\tconfigFile := path.ReplaceTildePrefixWithHomeDir(config)\n\n\tabs, err := filepath.Abs(configFile)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn filepath.Clean(configFile)\n\t}\n\n\treturn abs\n}\n\ntype hashWriter interface {\n\tWrite(p []byte) (n int, err error)\n}\n\nfunc Parse(configFile string) (*Config, error) {\n\tdefer log.Trace(time.Now())\n\n\tif configFile == \"\" {\n\t\tlog.Debug(\"no config file specified\")\n\t\treturn nil, ErrNoConfig\n\t}\n\n\tconfigFile = resolveConfigLocation(configFile)\n\n\tconfigDSC := DSC()\n\tconfigDSC.Load()\n\tconfigDSC.Add(configFile)\n\n\tdefer configDSC.Save()\n\n\th := fnv.New64a()\n\n\tcfg, err := read(configFile, h)\n\tif err != nil {\n\t\tlog.Errorf(\"failed to read config: %s\", configFile)\n\t\treturn nil, err\n\t}\n\n\tparentFolder := filepath.Dir(configFile)\n\n\tfor cfg.Extends != \"\" {\n\t\tcfg.Extends = resolvePath(cfg.Extends, parentFolder)\n\t\tbase, err := read(cfg.Extends, h)\n\t\tif err != nil {\n\t\t\tlog.Errorf(\"failed to read extended config: %s\", cfg.Extends)\n\t\t\tbreak\n\t\t}\n\n\t\tconfigDSC.Add(cfg.Extends)\n\n\t\terr = base.merge(cfg)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tbreak\n\t\t}\n\n\t\tcfg = base\n\t}\n\n\tcfg.Source = configFile\n\tcfg.hash = h.Sum64()\n\t// Migrate segment properties to options for TOML configs\n\t// (go-toml/v2 doesn't support custom unmarshalers)\n\tcfg.migrateSegmentProperties()\n\n\tcfg.toggleSegments()\n\n\tif cfg.Upgrade == nil {\n\t\tcfg.Upgrade = &upgrade.Config{\n\t\t\tSource:        upgrade.CDN,\n\t\t\tDisplayNotice: cfg.UpgradeNotice,\n\t\t\tAuto:          cfg.AutoUpgrade,\n\t\t\tInterval:      cache.ONEWEEK,\n\t\t}\n\t}\n\n\tif cfg.Upgrade.Interval.IsEmpty() {\n\t\tcfg.Upgrade.Interval = cache.ONEWEEK\n\t}\n\n\treturn cfg, nil\n}\n\nfunc resolvePath(configFile, parentFolder string) string {\n\tif url, OK := isTheme(configFile); OK {\n\t\treturn url\n\t}\n\n\tif strings.HasPrefix(configFile, \"https://\") {\n\t\treturn configFile\n\t}\n\n\tconfigFile = path.ReplaceTildePrefixWithHomeDir(configFile)\n\n\tif filepath.IsAbs(configFile) {\n\t\treturn configFile\n\t}\n\n\treturn filepath.Join(parentFolder, configFile)\n}\n\nfunc read(configFile string, h hashWriter) (*Config, error) {\n\tdefer log.Trace(time.Now())\n\n\tif configFile == \"\" {\n\t\tlog.Debug(\"no config file specified, using default\")\n\t\treturn Default(nil), nil\n\t}\n\n\tvar cfg Config\n\tcfg.Source = configFile\n\tcfg.Format = strings.TrimPrefix(filepath.Ext(configFile), \".\")\n\n\tdata, err := getData(configFile)\n\tif err != nil {\n\t\t// Determine the type of error\n\t\tif strings.HasPrefix(configFile, \"https://\") {\n\t\t\tlog.Errorf(\"failed to fetch config from URL: %v\", err)\n\t\t\treturn nil, ErrURLFetch\n\t\t}\n\t\tif errors.Is(err, os.ErrNotExist) {\n\t\t\tlog.Errorf(\"config file not found: %v\", err)\n\t\t\treturn nil, ErrFileNotFound\n\t\t}\n\t\tlog.Errorf(\"failed to read config: %v\", err)\n\t\treturn nil, ErrFileNotFound\n\t}\n\n\tvar parseErr error\n\tswitch cfg.Format {\n\tcase YAML, YML:\n\t\tcfg.Format = YAML\n\t\tparseErr = yaml.Unmarshal(data, &cfg)\n\tcase JSONC, JSON:\n\t\tcfg.Format = JSON\n\n\t\tstr := jsonutil.StripComments(string(data))\n\t\tdata = []byte(str)\n\n\t\tdecoder := json.NewDecoder(bytes.NewReader(data))\n\t\tparseErr = decoder.Decode(&cfg)\n\tcase TOML, TML:\n\t\tcfg.Format = TOML\n\t\tparseErr = toml.Unmarshal(data, &cfg)\n\tdefault:\n\t\tlog.Errorf(\"unsupported config file format: %s\", cfg.Format)\n\t\treturn nil, ErrInvalidExtension\n\t}\n\n\tif parseErr != nil {\n\t\tlog.Errorf(\"failed to parse config: %v\", parseErr)\n\t\treturn nil, ErrParse\n\t}\n\n\t_, err = h.Write(data)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\treturn &cfg, nil\n}\n\nfunc getData(configFile string) ([]byte, error) {\n\tif !strings.HasPrefix(configFile, \"https://\") {\n\t\treturn os.ReadFile(configFile)\n\t}\n\n\treturn http.Download(configFile, true)\n}\n\n// isCygwin checks if we're running in Cygwin environment\nfunc isCygwin() bool {\n\treturn runtimelib.GOOS == \"windows\" && len(os.Getenv(\"OSTYPE\")) > 0\n}\n\nfunc isTheme(config string) (string, bool) {\n\tthemes := map[string]string{\n\t\t\"1_shell\":                  \"1_shell.omp.json\",\n\t\t\"m365princess\":             \"M365Princess.omp.json\",\n\t\t\"agnoster\":                 \"agnoster.omp.json\",\n\t\t\"agnoster.minimal\":         \"agnoster.minimal.omp.json\",\n\t\t\"agnosterplus\":             \"agnosterplus.omp.json\",\n\t\t\"aliens\":                   \"aliens.omp.json\",\n\t\t\"amro\":                     \"amro.omp.json\",\n\t\t\"atomic\":                   \"atomic.omp.json\",\n\t\t\"atomicbit\":                \"atomicBit.omp.json\",\n\t\t\"avit\":                     \"avit.omp.json\",\n\t\t\"blue-owl\":                 \"blue-owl.omp.json\",\n\t\t\"blueish\":                  \"blueish.omp.json\",\n\t\t\"bubbles\":                  \"bubbles.omp.json\",\n\t\t\"bubblesextra\":             \"bubblesextra.omp.json\",\n\t\t\"bubblesline\":              \"bubblesline.omp.json\",\n\t\t\"capr4n\":                   \"capr4n.omp.json\",\n\t\t\"catppuccin\":               \"catppuccin.omp.json\",\n\t\t\"catppuccin_frappe\":        \"catppuccin_frappe.omp.json\",\n\t\t\"catppuccin_latte\":         \"catppuccin_latte.omp.json\",\n\t\t\"catppuccin_macchiato\":     \"catppuccin_macchiato.omp.json\",\n\t\t\"catppuccin_mocha\":         \"catppuccin_mocha.omp.json\",\n\t\t\"cert\":                     \"cert.omp.json\",\n\t\t\"chips\":                    \"chips.omp.json\",\n\t\t\"cinnamon\":                 \"cinnamon.omp.json\",\n\t\t\"clean-detailed\":           \"clean-detailed.omp.json\",\n\t\t\"cloud-context\":            \"cloud-context.omp.json\",\n\t\t\"cloud-native-azure\":       \"cloud-native-azure.omp.json\",\n\t\t\"cobalt2\":                  \"cobalt2.omp.json\",\n\t\t\"craver\":                   \"craver.omp.json\",\n\t\t\"darkblood\":                \"darkblood.omp.json\",\n\t\t\"devious-diamonds\":         \"devious-diamonds.omp.yaml\",\n\t\t\"di4am0nd\":                 \"di4am0nd.omp.json\",\n\t\t\"dracula\":                  \"dracula.omp.json\",\n\t\t\"easy-term\":                \"easy-term.omp.json\",\n\t\t\"emodipt\":                  \"emodipt.omp.json\",\n\t\t\"emodipt-extend\":           \"emodipt-extend.omp.json\",\n\t\t\"fish\":                     \"fish.omp.json\",\n\t\t\"free-ukraine\":             \"free-ukraine.omp.json\",\n\t\t\"froczh\":                   \"froczh.omp.json\",\n\t\t\"glowsticks\":               \"glowsticks.omp.yaml\",\n\t\t\"gmay\":                     \"gmay.omp.json\",\n\t\t\"grandpa-style\":            \"grandpa-style.omp.json\",\n\t\t\"gruvbox\":                  \"gruvbox.omp.json\",\n\t\t\"half-life\":                \"half-life.omp.json\",\n\t\t\"honukai\":                  \"honukai.omp.json\",\n\t\t\"hotstick.minimal\":         \"hotstick.minimal.omp.json\",\n\t\t\"hul10\":                    \"hul10.omp.json\",\n\t\t\"hunk\":                     \"hunk.omp.json\",\n\t\t\"huvix\":                    \"huvix.omp.json\",\n\t\t\"if_tea\":                   \"if_tea.omp.json\",\n\t\t\"illusi0n\":                 \"illusi0n.omp.json\",\n\t\t\"iterm2\":                   \"iterm2.omp.json\",\n\t\t\"jandedobbeleer\":           \"jandedobbeleer.omp.json\",\n\t\t\"jblab_2021\":               \"jblab_2021.omp.json\",\n\t\t\"jonnychipz\":               \"jonnychipz.omp.json\",\n\t\t\"json\":                     \"json.omp.json\",\n\t\t\"jtracey93\":                \"jtracey93.omp.json\",\n\t\t\"jv_sitecorian\":            \"jv_sitecorian.omp.json\",\n\t\t\"kali\":                     \"kali.omp.json\",\n\t\t\"kushal\":                   \"kushal.omp.json\",\n\t\t\"lambda\":                   \"lambda.omp.json\",\n\t\t\"lambdageneration\":         \"lambdageneration.omp.json\",\n\t\t\"larserikfinholt\":          \"larserikfinholt.omp.json\",\n\t\t\"lightgreen\":               \"lightgreen.omp.json\",\n\t\t\"marcduiker\":               \"marcduiker.omp.json\",\n\t\t\"markbull\":                 \"markbull.omp.json\",\n\t\t\"material\":                 \"material.omp.json\",\n\t\t\"microverse-power\":         \"microverse-power.omp.json\",\n\t\t\"mojada\":                   \"mojada.omp.json\",\n\t\t\"montys\":                   \"montys.omp.json\",\n\t\t\"mt\":                       \"mt.omp.json\",\n\t\t\"multiverse-neon\":          \"multiverse-neon.omp.json\",\n\t\t\"negligible\":               \"negligible.omp.json\",\n\t\t\"neko\":                     \"neko.omp.json\",\n\t\t\"night-owl\":                \"night-owl.omp.json\",\n\t\t\"nordtron\":                 \"nordtron.omp.json\",\n\t\t\"nu4a\":                     \"nu4a.omp.json\",\n\t\t\"onehalf.minimal\":          \"onehalf.minimal.omp.json\",\n\t\t\"paradox\":                  \"paradox.omp.json\",\n\t\t\"pararussel\":               \"pararussel.omp.json\",\n\t\t\"patriksvensson\":           \"patriksvensson.omp.json\",\n\t\t\"peru\":                     \"peru.omp.json\",\n\t\t\"pixelrobots\":              \"pixelrobots.omp.json\",\n\t\t\"plague\":                   \"plague.omp.json\",\n\t\t\"poshmon\":                  \"poshmon.omp.json\",\n\t\t\"powerlevel10k_classic\":    \"powerlevel10k_classic.omp.json\",\n\t\t\"powerlevel10k_lean\":       \"powerlevel10k_lean.omp.json\",\n\t\t\"powerlevel10k_modern\":     \"powerlevel10k_modern.omp.json\",\n\t\t\"powerlevel10k_rainbow\":    \"powerlevel10k_rainbow.omp.json\",\n\t\t\"powerline\":                \"powerline.omp.json\",\n\t\t\"probua.minimal\":           \"probua.minimal.omp.json\",\n\t\t\"pure\":                     \"pure.omp.json\",\n\t\t\"quick-term\":               \"quick-term.omp.json\",\n\t\t\"remk\":                     \"remk.omp.json\",\n\t\t\"robbyrussell\":             \"robbyrussell.omp.json\",\n\t\t\"rudolfs-dark\":             \"rudolfs-dark.omp.json\",\n\t\t\"rudolfs-light\":            \"rudolfs-light.omp.json\",\n\t\t\"sim-web\":                  \"sim-web.omp.json\",\n\t\t\"slim\":                     \"slim.omp.json\",\n\t\t\"slimfat\":                  \"slimfat.omp.json\",\n\t\t\"smoothie\":                 \"smoothie.omp.json\",\n\t\t\"sonicboom_dark\":           \"sonicboom_dark.omp.json\",\n\t\t\"sonicboom_light\":          \"sonicboom_light.omp.json\",\n\t\t\"sorin\":                    \"sorin.omp.json\",\n\t\t\"space\":                    \"space.omp.json\",\n\t\t\"spaceship\":                \"spaceship.omp.json\",\n\t\t\"star\":                     \"star.omp.json\",\n\t\t\"stelbent-compact.minimal\": \"stelbent-compact.minimal.omp.json\",\n\t\t\"stelbent.minimal\":         \"stelbent.minimal.omp.json\",\n\t\t\"takuya\":                   \"takuya.omp.json\",\n\t\t\"the-unnamed\":              \"the-unnamed.omp.json\",\n\t\t\"thecyberden\":              \"thecyberden.omp.json\",\n\t\t\"tiwahu\":                   \"tiwahu.omp.json\",\n\t\t\"tokyo\":                    \"tokyo.omp.json\",\n\t\t\"tokyonight_storm\":         \"tokyonight_storm.omp.json\",\n\t\t\"tonybaloney\":              \"tonybaloney.omp.json\",\n\t\t\"uew\":                      \"uew.omp.json\",\n\t\t\"unicorn\":                  \"unicorn.omp.json\",\n\t\t\"velvet\":                   \"velvet.omp.json\",\n\t\t\"wholespace\":               \"wholespace.omp.json\",\n\t\t\"wopian\":                   \"wopian.omp.json\",\n\t\t\"xtoys\":                    \"xtoys.omp.json\",\n\t\t\"ys\":                       \"ys.omp.json\",\n\t\t\"zash\":                     \"zash.omp.json\",\n\t}\n\n\tthemeFile, OK := themes[config]\n\tif !OK {\n\t\tlog.Debug(config, \"is not a theme\")\n\t\treturn \"\", false\n\t}\n\n\tlog.Debug(config, \"is a theme\")\n\n\tif themeFilePath, err := getMSIXThemePath(themeFile); err == nil {\n\t\treturn themeFilePath, true\n\t}\n\n\tlog.Debug(\"building theme URL for:\", themeFile)\n\turl := fmt.Sprintf(\"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/refs/tags/v%s/themes/%s\", build.Version, themeFile)\n\treturn url, true\n}\n\nfunc getMSIXThemePath(themeFile string) (string, error) {\n\tlog.Trace(time.Now(), themeFile)\n\n\t// For MSIX packages, the executable location is the package root\n\texePath, err := os.Executable()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\n\tthemeFilePath := filepath.Join(filepath.Dir(exePath), \"themes\", themeFile)\n\tif _, err := os.Stat(themeFilePath); err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\n\tlog.Debug(\"found theme in MSIX installation:\", themeFilePath)\n\treturn themeFilePath, nil\n}\n"
  },
  {
    "path": "src/config/merge.go",
    "content": "package config\n\nimport (\n\t\"errors\"\n\t\"reflect\"\n\t\"slices\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype matcher interface {\n\tkey() any\n}\n\ntype matchMap[T matcher] map[any]T\n\nfunc (mm *matchMap[T]) hasMatch(index int, m T) (T, bool) {\n\tfor _, item := range *mm {\n\t\tif item.key() == index {\n\t\t\treturn item, true\n\t\t}\n\t}\n\n\tmatch, OK := (*mm)[m.key()]\n\treturn match, OK\n}\n\nfunc (mm *matchMap[T]) add(m T) {\n\tif *mm == nil {\n\t\t*mm = make(matchMap[T])\n\t}\n\n\t(*mm)[m.key()] = m\n}\n\nfunc (mm *matchMap[T]) remove(m T) {\n\tdelete(*mm, m.key())\n}\n\nfunc createMatchMap[T matcher](items []T) matchMap[T] {\n\tmm := make(matchMap[T])\n\tfor _, item := range items {\n\t\tif any(item) != nil {\n\t\t\tmm.add(item)\n\t\t}\n\t}\n\treturn mm\n}\n\nfunc (cfg *Config) merge(override *Config) error {\n\tif cfg == nil || override == nil {\n\t\treturn errors.New(\"configs cannot be nil\")\n\t}\n\n\tnextExtends := cfg.Extends\n\n\terr := merge(override, cfg, \"Blocks\", \"Source\", \"Format\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\toverrideBlockMap := createMatchMap(override.Blocks)\n\n\tfor i := range cfg.Blocks {\n\t\toverrideBlock, exists := overrideBlockMap.hasMatch(i, cfg.Blocks[i])\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\t// remove the block from the override map so we don't match it again\n\t\toverrideBlockMap.remove(overrideBlock)\n\n\t\terr = merge(overrideBlock, cfg.Blocks[i], \"Segments\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\toverrideSegmentMap := createMatchMap(overrideBlock.Segments)\n\n\t\tfor k := range cfg.Blocks[i].Segments {\n\t\t\toverrideSegment, exists := overrideSegmentMap.hasMatch(k, cfg.Blocks[i].Segments[k])\n\t\t\tif !exists {\n\t\t\t\tlog.Debugf(\"No matching segment found for %s in block %s\", cfg.Blocks[i].Segments[k].Type, cfg.Blocks[i].Type)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// remove the block from the override map so we don't match it again\n\t\t\toverrideSegmentMap.remove(overrideSegment)\n\n\t\t\tbaseSegment := cfg.Blocks[i].Segments[k]\n\n\t\t\tif baseSegment.Type != overrideSegment.Type {\n\t\t\t\tlog.Debugf(\"Replacing segment %s with %s in block %s\", baseSegment.Type, overrideSegment.Type, cfg.Blocks[i].Type)\n\t\t\t\tcfg.Blocks[i].Segments[k] = overrideSegment\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\terr = merge(overrideSegment, baseSegment)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// add any remaining segments that were not matched\n\t\tfor _, segment := range overrideSegmentMap {\n\t\t\tlog.Debugf(\"Adding segment %s to block %s\", segment.Type, cfg.Blocks[i].Type)\n\t\t\tcfg.Blocks[i].Segments = append(cfg.Blocks[i].Segments, segment)\n\t\t}\n\t}\n\n\tcfg.Extends = nextExtends\n\tcfg.extended = true\n\n\treturn nil\n}\n\nfunc merge(override, base any, skipFields ...string) error {\n\tif base == nil || override == nil {\n\t\treturn errors.New(\"config to merge cannot be nil\")\n\t}\n\n\toverrideValue := reflect.ValueOf(override).Elem()\n\tbaseValue := reflect.ValueOf(base).Elem()\n\toverrideType := overrideValue.Type()\n\n\tfor i := 0; i < overrideValue.NumField(); i++ {\n\t\tfield := overrideType.Field(i)\n\n\t\tif !field.IsExported() {\n\t\t\tcontinue\n\t\t}\n\n\t\toverrideField := overrideValue.Field(i)\n\t\tbaseField := baseValue.FieldByName(field.Name)\n\n\t\t// Skip unexported fields or fields that can't be set\n\t\tif isZeroValue(overrideField) || !baseField.CanSet() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip internal fields that shouldn't be merged\n\t\tif slices.Contains(skipFields, field.Name) {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Special handling for slices - merge instead of replace\n\t\tif overrideField.Kind() == reflect.Slice {\n\t\t\tmergeSlices(overrideField, baseField)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Special handling for maps - merge instead of replace\n\t\tif overrideField.Kind() == reflect.Map {\n\t\t\tmergeMaps(overrideField, baseField)\n\t\t\tcontinue\n\t\t}\n\n\t\tif baseField.CanSet() {\n\t\t\tbaseField.Set(overrideField)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc isZeroValue(v reflect.Value) bool {\n\tswitch v.Kind() { //nolint: exhaustive\n\tcase reflect.Slice, reflect.Map:\n\t\treturn v.IsNil() || v.Len() == 0\n\tcase reflect.Ptr:\n\t\treturn v.IsNil()\n\tcase reflect.String:\n\t\treturn v.String() == \"\"\n\tcase reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn false\n\tdefault:\n\t\treturn v.IsZero()\n\t}\n}\n\nfunc mergeSlices(override, base reflect.Value) {\n\tif base.IsNil() && !override.IsNil() {\n\t\tbase.Set(override)\n\t\treturn\n\t}\n\n\tif !base.IsNil() && !override.IsNil() {\n\t\tnewSlice := reflect.AppendSlice(base, override)\n\t\tbase.Set(newSlice)\n\t}\n}\n\nfunc mergeMaps(override, base reflect.Value) {\n\tif base.IsNil() && !override.IsNil() {\n\t\tbase.Set(override)\n\t\treturn\n\t}\n\n\tif !base.IsNil() && !override.IsNil() {\n\t\t// Merge maps - cfg values override base values\n\t\tfor _, key := range override.MapKeys() {\n\t\t\tbase.SetMapIndex(key, override.MapIndex(key))\n\t\t}\n\t}\n\n\tif base.IsNil() {\n\t\t// Initialize empty map if both are nil but base has the type\n\t\tbase.Set(reflect.MakeMap(base.Type()))\n\t}\n}\n"
  },
  {
    "path": "src/config/merge_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestConfigMerge(t *testing.T) {\n\ttestCases := []struct {\n\t\tbaseConfig     *Config\n\t\toverrideConfig *Config\n\t\texpectedResult *Config\n\t\tname           string\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tname: \"merge basic options\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tVersion:     3,\n\t\t\t\tFinalSpace:  true,\n\t\t\t\tAsync:       false,\n\t\t\t\tAccentColor: \"red\",\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tVersion:    3,\n\t\t\t\tFinalSpace: false,\n\t\t\t\tAsync:      true,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tVersion:     3,\n\t\t\t\tFinalSpace:  false,\n\t\t\t\tAsync:       true,\n\t\t\t\tAccentColor: \"red\",\n\t\t\t\textended:    true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge with nil override\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tVersion:    3,\n\t\t\t\tFinalSpace: true,\n\t\t\t},\n\t\t\toverrideConfig: nil,\n\t\t\texpectedResult: &Config{\n\t\t\t\tVersion:    3,\n\t\t\t\tFinalSpace: true,\n\t\t\t},\n\t\t\texpectError: true,\n\t\t},\n\t\t{\n\t\t\tname: \"merge console title template\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tConsoleTitleTemplate: \"Base Title\",\n\t\t\t\tVersion:              3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tConsoleTitleTemplate: \"Override Title\",\n\t\t\t\tVersion:              3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tConsoleTitleTemplate: \"Override Title\",\n\t\t\t\tVersion:              3,\n\t\t\t\textended:             true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge variables map\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tVar: map[string]any{\n\t\t\t\t\t\"base_var\":   \"base_value\",\n\t\t\t\t\t\"shared_var\": \"base_shared\",\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tVar: map[string]any{\n\t\t\t\t\t\"added_var\":  \"added_value\",\n\t\t\t\t\t\"shared_var\": \"override_shared\",\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tVar: map[string]any{\n\t\t\t\t\t\"base_var\":   \"base_value\",\n\t\t\t\t\t\"added_var\":  \"added_value\",\n\t\t\t\t\t\"shared_var\": \"override_shared\",\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge blocks with matching alignment\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Options: options.Map{\"style\": \"full\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge blocks with different segment types\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Alias: \"override\", Options: options.Map{\"style\": \"full\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"git\", Alias: \"override\", Options: options.Map{\"branch_icon\": \"branch\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"git\", Alias: \"override\", Options: options.Map{\"branch_icon\": \"branch\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge segments by index\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Options: options.Map{\"style\": \"full\"}},\n\t\t\t\t\t\t\t{Type: \"git\", Options: options.Map{\"branch_icon\": \"\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Index: 1, Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Index: 1, Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t\t{Type: \"git\", Options: options.Map{\"branch_icon\": \"\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge block by index\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Options: options.Map{\"style\": \"full\"}},\n\t\t\t\t\t\t\t{Type: \"git\", Options: options.Map{\"branch_icon\": \"\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tIndex: 1,\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Index: 1, Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{\n\t\t\t\t\t\tAlignment: \"left\",\n\t\t\t\t\t\tType:      \"prompt\",\n\t\t\t\t\t\tIndex:     1,\n\t\t\t\t\t\tSegments: []*Segment{\n\t\t\t\t\t\t\t{Type: \"path\", Index: 1, Options: options.Map{\"style\": \"short\"}},\n\t\t\t\t\t\t\t{Type: \"git\", Options: options.Map{\"branch_icon\": \"\"}},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge palette colors\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tPalette: color.Palette{\n\t\t\t\t\t\"primary\":   \"blue\",\n\t\t\t\t\t\"secondary\": \"green\",\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tPalette: color.Palette{\n\t\t\t\t\t\"primary\": \"red\",\n\t\t\t\t\t\"accent\":  \"yellow\",\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tPalette: color.Palette{\n\t\t\t\t\t\"primary\":   \"red\",\n\t\t\t\t\t\"secondary\": \"green\",\n\t\t\t\t\t\"accent\":    \"yellow\",\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"preserve extends field\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tExtends: \"/path/to/base.json\",\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tExtends: \"/path/to/override.json\",\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tExtends:  \"/path/to/base.json\",\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t\t{\n\t\t\tname: \"merge tooltips slice\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tTooltips: []*Segment{\n\t\t\t\t\t{Type: \"git\", Tips: []string{\"git\"}},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tTooltips: []*Segment{\n\t\t\t\t\t{Type: \"path\", Tips: []string{\"pwd\"}},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectedResult: &Config{\n\t\t\t\tTooltips: []*Segment{\n\t\t\t\t\t{Type: \"git\", Tips: []string{\"git\"}},\n\t\t\t\t\t{Type: \"path\", Tips: []string{\"pwd\"}},\n\t\t\t\t},\n\t\t\t\tVersion:  3,\n\t\t\t\textended: true,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.baseConfig.merge(tc.overrideConfig)\n\n\t\t\tif tc.expectError {\n\t\t\t\trequire.Error(t, err, tc.name)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err, tc.name)\n\t\t\tassert.EqualExportedValues(t, tc.expectedResult, tc.baseConfig, tc.name)\n\t\t})\n\t}\n}\n\nfunc TestConfigMergeEdgeCases(t *testing.T) {\n\ttestCases := []struct {\n\t\tbaseConfig     *Config\n\t\toverrideConfig *Config\n\t\tname           string\n\t\texpectError    bool\n\t}{\n\t\t{\n\t\t\tname:           \"nil base config\",\n\t\t\tbaseConfig:     nil,\n\t\t\toverrideConfig: &Config{Version: 3},\n\t\t\texpectError:    true,\n\t\t},\n\t\t{\n\t\t\tname:           \"empty configs\",\n\t\t\tbaseConfig:     &Config{},\n\t\t\toverrideConfig: &Config{},\n\t\t\texpectError:    false,\n\t\t},\n\t\t{\n\t\t\tname: \"override with empty blocks\",\n\t\t\tbaseConfig: &Config{\n\t\t\t\tBlocks: []*Block{\n\t\t\t\t\t{Alignment: \"left\", Type: \"prompt\"},\n\t\t\t\t},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\toverrideConfig: &Config{\n\t\t\t\tBlocks:  []*Block{},\n\t\t\t\tVersion: 3,\n\t\t\t},\n\t\t\texpectError: false,\n\t\t},\n\t}\n\n\tfor _, tc := range testCases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\terr := tc.baseConfig.merge(tc.overrideConfig)\n\n\t\t\tif tc.expectError {\n\t\t\t\trequire.Error(t, err, tc.name)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\trequire.NoError(t, err, tc.name)\n\t\t\tif tc.baseConfig != nil {\n\t\t\t\tassert.True(t, tc.baseConfig.extended, tc.name)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/config/migrate_glyphs.go",
    "content": "package config\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\ntype ConnectionError struct {\n\treason string\n}\n\nfunc (f *ConnectionError) Error() string {\n\treturn f.reason\n}\n\ntype codePoints map[uint64]uint64\n\nfunc getGlyphCodePoints() (codePoints, error) {\n\tvar codePoints = make(codePoints)\n\n\tbytes, err := http.Download(\"https://ohmyposh.dev/codepoints.csv\", false)\n\tif err != nil {\n\t\treturn codePoints, &ConnectionError{reason: err.Error()}\n\t}\n\n\tlines := strings.SplitSeq(string(bytes), \"\\n\")\n\n\tfor line := range lines {\n\t\tfields := strings.Split(line, \",\")\n\t\tif len(fields) < 2 {\n\t\t\tcontinue\n\t\t}\n\n\t\toldGlyph, err := strconv.ParseUint(fields[0], 16, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tnewGlyph, err := strconv.ParseUint(fields[1], 16, 32)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tcodePoints[oldGlyph] = newGlyph\n\t}\n\n\treturn codePoints, nil\n}\n\nfunc EscapeGlyphs(s string, migrate bool) string {\n\tshouldExclude := func(r rune) bool {\n\t\tif r < 0x1000 { // Basic Multilingual Plane\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x1F600 && r < 0x1F64F { // Emoticons\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x1F300 && r < 0x1F5FF { // Misc Symbols and Pictographs\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x1F680 && r < 0x1F6FF { // Transport and Map\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x2600 && r < 0x26FF { // Misc symbols\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x2700 && r < 0x27BF { // Dingbats\n\t\t\treturn true\n\t\t}\n\t\tif r > 0xFE00 && r < 0xFE0F { // Variation Selectors\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x1F900 && r < 0x1F9FF { // Supplemental Symbols and Pictographs\n\t\t\treturn true\n\t\t}\n\t\tif r > 0x1F1E6 && r < 0x1F1FF { // Flags\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tvar cp codePoints\n\tvar err error\n\tif migrate {\n\t\tcp, err = getGlyphCodePoints()\n\t\tif err != nil {\n\t\t\tmigrate = false\n\t\t}\n\t}\n\n\tsb := text.NewBuilder()\n\tfor _, r := range s {\n\t\t// exclude regular characters and emojis\n\t\tif shouldExclude(r) {\n\t\t\tsb.WriteRune(r)\n\t\t\tcontinue\n\t\t}\n\n\t\tif migrate {\n\t\t\tif val, OK := cp[uint64(r)]; OK {\n\t\t\t\tr = rune(val)\n\t\t\t}\n\t\t}\n\n\t\tif r > 0x10000 {\n\t\t\t// calculate surrogate pairs\n\t\t\tone := 0xd800 + (((r - 0x10000) >> 10) & 0x3ff)\n\t\t\ttwo := 0xdc00 + ((r - 0x10000) & 0x3ff)\n\t\t\tquoted := fmt.Sprintf(\"\\\\u%04x\\\\u%04x\", one, two)\n\t\t\tsb.WriteString(quoted)\n\t\t\tcontinue\n\t\t}\n\n\t\tquoted := fmt.Sprintf(\"\\\\u%04x\", r)\n\t\tsb.WriteString(quoted)\n\t}\n\n\treturn sb.String()\n}\n"
  },
  {
    "path": "src/config/migrate_glyphs_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetCodePoints(t *testing.T) {\n\tcodepoints, err := getGlyphCodePoints()\n\tif connectionError, ok := err.(*ConnectionError); ok {\n\t\tt.Log(connectionError.Error())\n\t\treturn\n\t}\n\tassert.Equal(t, 1939, len(codepoints))\n}\n\nfunc TestEscapeGlyphs(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"󰉋\", Expected: \"\\\\udb80\\\\ude4b\"},\n\t\t{Input: \"a\", Expected: \"a\"},\n\t\t{Input: \"\\ue0b4\", Expected: \"\\\\ue0b4\"},\n\t\t{Input: \"\\ufd03\", Expected: \"\\\\ufd03\"},\n\t\t{Input: \"}\", Expected: \"}\"},\n\t\t{Input: \"🏚\", Expected: \"🏚\"},\n\t\t{Input: \"\\U000f0bc9\", Expected: \"\\\\udb82\\\\udfc9\"},\n\t\t{Input: \"󰯉\", Expected: \"\\\\udb82\\\\udfc9\"},\n\t}\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, EscapeGlyphs(tc.Input, false), tc.Input)\n\t}\n}\n"
  },
  {
    "path": "src/config/responsive.go",
    "content": "package config\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\nfunc shouldHideForWidth(env runtime.Environment, minWidth, maxWidth int) bool {\n\tif maxWidth == 0 && minWidth == 0 {\n\t\treturn false\n\t}\n\twidth, err := env.TerminalWidth()\n\tif err != nil {\n\t\treturn false\n\t}\n\tif minWidth > 0 && maxWidth > 0 {\n\t\treturn width < minWidth || width > maxWidth\n\t}\n\tif maxWidth > 0 && width > maxWidth {\n\t\treturn true\n\t}\n\tif minWidth > 0 && width < minWidth {\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/config/responsive_test.go",
    "content": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestShouldHideForWidth(t *testing.T) {\n\tcases := []struct {\n\t\tError    error\n\t\tCase     string\n\t\tMinWidth int\n\t\tMaxWidth int\n\t\tWidth    int\n\t\tExpected bool\n\t}{\n\t\t{Case: \"No settings\"},\n\t\t{Case: \"Min cols - hide\", MinWidth: 10, Width: 9, Expected: true},\n\t\t{Case: \"Min cols - show\", MinWidth: 10, Width: 20, Expected: false},\n\t\t{Case: \"Max cols - hide\", MaxWidth: 10, Width: 11, Expected: true},\n\t\t{Case: \"Max cols - show\", MaxWidth: 10, Width: 8, Expected: false},\n\t\t{Case: \"Min & Max cols - hide\", MinWidth: 10, MaxWidth: 20, Width: 21, Expected: true},\n\t\t{Case: \"Min & Max cols - hide 2\", MinWidth: 10, MaxWidth: 20, Width: 8, Expected: true},\n\t\t{Case: \"Min & Max cols - show\", MinWidth: 10, MaxWidth: 20, Width: 11, Expected: false},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"TerminalWidth\").Return(tc.Width, tc.Error)\n\t\tgot := shouldHideForWidth(env, tc.MinWidth, tc.MaxWidth)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/config/segment.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"slices\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\trunjobs \"github.com/jandedobbeleer/oh-my-posh/src/runtime/jobs\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"go.yaml.in/yaml/v3\"\n\tc \"golang.org/x/text/cases\"\n\t\"golang.org/x/text/language\"\n)\n\n// SegmentStyle the style of segment, for more information, see the constants\ntype SegmentStyle string\n\nfunc (s *SegmentStyle) resolve(context any) SegmentStyle {\n\tvalue, err := template.Render(string(*s), context)\n\n\t// default to Plain\n\tif err != nil || value == \"\" {\n\t\treturn Plain\n\t}\n\n\treturn SegmentStyle(value)\n}\n\ntype Segment struct {\n\twriter                 SegmentWriter\n\tenv                    runtime.Environment\n\tOptions                options.Map `json:\"options,omitempty\" toml:\"options,omitempty\" yaml:\"options,omitempty\"`\n\tProperties             options.Map `json:\"-\" toml:\"properties,omitempty\" yaml:\"-\"`\n\tCache                  *Cache      `json:\"cache,omitempty\" toml:\"cache,omitempty\" yaml:\"cache,omitempty\"`\n\tAlias                  string      `json:\"alias,omitempty\" toml:\"alias,omitempty\" yaml:\"alias,omitempty\"`\n\tstyleCache             SegmentStyle\n\tname                   string\n\tLeadingDiamond         string         `json:\"leading_diamond,omitempty\" toml:\"leading_diamond,omitempty\" yaml:\"leading_diamond,omitempty\"`\n\tTrailingDiamond        string         `json:\"trailing_diamond,omitempty\" toml:\"trailing_diamond,omitempty\" yaml:\"trailing_diamond,omitempty\"`\n\tTemplate               string         `json:\"template,omitempty\" toml:\"template,omitempty\" yaml:\"template,omitempty\"`\n\tForeground             color.Ansi     `json:\"foreground,omitempty\" toml:\"foreground,omitempty\" yaml:\"foreground,omitempty\"`\n\tTemplatesLogic         template.Logic `json:\"templates_logic,omitempty\" toml:\"templates_logic,omitempty\" yaml:\"templates_logic,omitempty\"`\n\tPowerlineSymbol        string         `json:\"powerline_symbol,omitempty\" toml:\"powerline_symbol,omitempty\" yaml:\"powerline_symbol,omitempty\"`\n\tBackground             color.Ansi     `json:\"background,omitempty\" toml:\"background,omitempty\" yaml:\"background,omitempty\"`\n\tFiller                 string         `json:\"filler,omitempty\" toml:\"filler,omitempty\" yaml:\"filler,omitempty\"`\n\tType                   SegmentType    `json:\"type,omitempty\" toml:\"type,omitempty\" yaml:\"type,omitempty\"`\n\tStyle                  SegmentStyle   `json:\"style,omitempty\" toml:\"style,omitempty\" yaml:\"style,omitempty\"`\n\tLeadingPowerlineSymbol string         `json:\"leading_powerline_symbol,omitempty\" toml:\"leading_powerline_symbol,omitempty\" yaml:\"leading_powerline_symbol,omitempty\"`\n\tPlaceholder            string         `json:\"placeholder,omitempty\" toml:\"placeholder,omitempty\" yaml:\"placeholder,omitempty\"`\n\tTips                   []string       `json:\"tips,omitempty\" toml:\"tips,omitempty\" yaml:\"tips,omitempty\"`\n\tBackgroundTemplates    template.List  `json:\"background_templates,omitempty\" toml:\"background_templates,omitempty\" yaml:\"background_templates,omitempty\"`\n\tTemplates              template.List  `json:\"templates,omitempty\" toml:\"templates,omitempty\" yaml:\"templates,omitempty\"`\n\tExcludeFolders         []string       `json:\"exclude_folders,omitempty\" toml:\"exclude_folders,omitempty\" yaml:\"exclude_folders,omitempty\"`\n\tIncludeFolders         []string       `json:\"include_folders,omitempty\" toml:\"include_folders,omitempty\" yaml:\"include_folders,omitempty\"`\n\tNeeds                  []string       `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tForegroundTemplates    template.List  `json:\"foreground_templates,omitempty\" toml:\"foreground_templates,omitempty\" yaml:\"foreground_templates,omitempty\"`\n\tIndex                  int            `json:\"index,omitempty\" toml:\"index,omitempty\" yaml:\"index,omitempty\"`\n\tMinWidth               int            `json:\"min_width,omitempty\" toml:\"min_width,omitempty\" yaml:\"min_width,omitempty\"`\n\tDuration               time.Duration  `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tNameLength             int            `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tMaxWidth               int            `json:\"max_width,omitempty\" toml:\"max_width,omitempty\" yaml:\"max_width,omitempty\"`\n\tTimeout                int            `json:\"timeout,omitempty\" toml:\"timeout,omitempty\" yaml:\"timeout,omitempty\"`\n\tNewline                bool           `json:\"newline,omitempty\" toml:\"newline,omitempty\" yaml:\"newline,omitempty\"`\n\tEnabled                bool           `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tInvertPowerline        bool           `json:\"invert_powerline,omitempty\" toml:\"invert_powerline,omitempty\" yaml:\"invert_powerline,omitempty\"`\n\tForce                  bool           `json:\"force,omitempty\" toml:\"force,omitempty\" yaml:\"force,omitempty\"`\n\trestored               bool           `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tToggled                bool           `json:\"toggled,omitempty\" toml:\"toggled,omitempty\" yaml:\"toggled,omitempty\"`\n\tPending                bool           `json:\"-\" toml:\"-\" yaml:\"-\"`\n\tInteractive            bool           `json:\"interactive,omitempty\" toml:\"interactive,omitempty\" yaml:\"interactive,omitempty\"`\n}\n\n// segmentAlias is used to avoid recursion during unmarshaling\ntype segmentAlias Segment\n\n// segmentAux is a helper struct that captures the legacy 'properties' field\ntype segmentAux struct {\n\tProperties options.Map `json:\"properties,omitempty\" yaml:\"properties,omitempty\" toml:\"properties,omitempty\"`\n\t*segmentAlias\n}\n\nfunc (segment *Segment) UnmarshalJSON(data []byte) error {\n\taux := &segmentAux{\n\t\tsegmentAlias: (*segmentAlias)(segment),\n\t}\n\n\tif err := json.Unmarshal(data, aux); err != nil {\n\t\treturn err\n\t}\n\n\t// Migrate 'properties' to 'options' if present\n\tif len(aux.Properties) > 0 && len(segment.Options) == 0 {\n\t\tsegment.Options = aux.Properties\n\t}\n\n\treturn nil\n}\n\nfunc (segment *Segment) UnmarshalYAML(node *yaml.Node) error {\n\t// Decode into a map to handle field renaming\n\tvar raw map[string]any\n\tif err := node.Decode(&raw); err != nil {\n\t\treturn err\n\t}\n\n\t// If 'properties' exists and 'options' doesn't, rename it\n\tif props, hasProps := raw[\"properties\"]; hasProps {\n\t\tif _, hasOptions := raw[\"options\"]; !hasOptions {\n\t\t\traw[\"options\"] = props\n\t\t\tdelete(raw, \"properties\")\n\t\t}\n\t}\n\n\t// Re-encode and decode into the struct\n\tmodifiedNode := &yaml.Node{}\n\tif err := modifiedNode.Encode(raw); err != nil {\n\t\treturn err\n\t}\n\n\treturn modifiedNode.Decode((*segmentAlias)(segment))\n}\n\n// MigratePropertiesToOptions migrates the deprecated Properties field to Options.\n// This is needed for TOML configs since go-toml/v2 doesn't support custom unmarshalers.\nfunc (segment *Segment) MigratePropertiesToOptions() {\n\tif len(segment.Properties) > 0 && len(segment.Options) == 0 {\n\t\tsegment.Options = segment.Properties\n\t\tsegment.Properties = nil\n\t}\n}\n\nfunc (segment *Segment) Name() string {\n\tif len(segment.name) != 0 {\n\t\treturn segment.name\n\t}\n\n\tname := segment.Alias\n\tif name == \"\" {\n\t\tname = c.Title(language.English).String(string(segment.Type))\n\t}\n\n\tsegment.name = name\n\treturn name\n}\n\nfunc (segment *Segment) Execute(env runtime.Environment) {\n\t// segment timings for debug purposes\n\tvar start time.Time\n\tif env.Flags().Debug {\n\t\tstart = time.Now()\n\t\tsegment.NameLength = len(segment.Name())\n\t\tdefer func() {\n\t\t\tsegment.Duration = time.Since(start)\n\t\t}()\n\t}\n\n\tdefer segment.evaluateNeeds()\n\n\terr := segment.MapSegmentWithWriter(env)\n\tif err != nil || !segment.shouldIncludeFolder() {\n\t\treturn\n\t}\n\n\tlog.Debugf(\"segment: %s\", segment.Name())\n\n\tif segment.isToggled() {\n\t\treturn\n\t}\n\n\tcacheRestored := segment.restoreCache()\n\tif cacheRestored && !env.Flags().Streaming {\n\t\treturn\n\t}\n\n\tif shouldHideForWidth(segment.env, segment.MinWidth, segment.MaxWidth) {\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\tif segment.Enabled {\n\t\t\ttemplate.Cache.AddSegmentData(segment.Name(), segment.writer)\n\t\t}\n\t}()\n\n\t// Create Job for this goroutine so child processes can be tracked and killed on timeout\n\tif err := runjobs.CreateJobForGoroutine(segment.Name()); err != nil {\n\t\tlog.Errorf(\"failed to create job for goroutine (segment: %s): %v\", segment.Name(), err)\n\t}\n\n\tsegment.Enabled = segment.writer.Enabled()\n}\n\nfunc (segment *Segment) Render(index int, force bool) bool {\n\t// Allow pending segments to render (they'll show \"...\" text)\n\tif !segment.Pending && !segment.Enabled && !force {\n\t\treturn false\n\t}\n\n\tif force {\n\t\tsegment.Force = true\n\t}\n\n\tsegment.writer.SetIndex(index)\n\n\ttext := segment.string()\n\n\t// Only update Enabled if segment is NOT pending (avoid race with Execute goroutine)\n\tif !segment.Pending {\n\t\tsegment.Enabled = segment.Force || len(strings.ReplaceAll(text, \" \", \"\")) > 0\n\n\t\tif !segment.Enabled {\n\t\t\ttemplate.Cache.RemoveSegmentData(segment.Name())\n\t\t\treturn false\n\t\t}\n\t}\n\n\tsegment.SetText(text)\n\tsegment.setCache()\n\n\t// We do this to make `.Text` available for a cross-segment reference in an extra prompt.\n\ttemplate.Cache.AddSegmentData(segment.Name(), segment.writer)\n\n\treturn true\n}\n\nfunc (segment *Segment) Text() string {\n\treturn segment.writer.Text()\n}\n\nfunc (segment *Segment) SetText(text string) {\n\tsegment.writer.SetText(text)\n}\n\nfunc (segment *Segment) ResolveForeground() color.Ansi {\n\tif len(segment.ForegroundTemplates) != 0 {\n\t\tmatch := segment.ForegroundTemplates.FirstMatch(segment.writer, segment.Foreground.String())\n\t\tsegment.Foreground = color.Ansi(match)\n\t}\n\n\treturn segment.Foreground\n}\n\nfunc (segment *Segment) ResolveBackground() color.Ansi {\n\tif len(segment.BackgroundTemplates) != 0 {\n\t\tmatch := segment.BackgroundTemplates.FirstMatch(segment.writer, segment.Background.String())\n\t\tsegment.Background = color.Ansi(match)\n\t}\n\n\treturn segment.Background\n}\n\nfunc (segment *Segment) ResolveStyle() SegmentStyle {\n\tif len(segment.styleCache) != 0 {\n\t\treturn segment.styleCache\n\t}\n\n\tsegment.styleCache = segment.Style.resolve(segment.writer)\n\n\treturn segment.styleCache\n}\n\nfunc (segment *Segment) IsPowerline() bool {\n\tstyle := segment.ResolveStyle()\n\treturn style == Powerline || style == Accordion\n}\n\nfunc (segment *Segment) HasEmptyDiamondAtEnd() bool {\n\tif segment.ResolveStyle() != Diamond {\n\t\treturn false\n\t}\n\n\treturn segment.TrailingDiamond == \"\"\n}\n\nfunc (segment *Segment) hasCache() bool {\n\treturn segment.Cache != nil && !segment.Cache.Duration.IsEmpty()\n}\n\nfunc (segment *Segment) isToggled() bool {\n\ttogglesMap, OK := cache.Get[map[string]bool](cache.Session, cache.TOGGLECACHE)\n\tif !OK || len(togglesMap) == 0 {\n\t\tlog.Debug(\"no toggles found\")\n\t\treturn false\n\t}\n\n\tsegmentName := segment.Alias\n\tif segmentName == \"\" {\n\t\tsegmentName = string(segment.Type)\n\t}\n\n\tif togglesMap[segmentName] {\n\t\tlog.Debugf(\"segment toggled off: %s\", segment.Name())\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (segment *Segment) restoreCache() bool {\n\tif !segment.hasCache() {\n\t\treturn false\n\t}\n\n\tkey, store := segment.cacheKeyAndStore()\n\tdata, OK := cache.Get[string](store, key)\n\tif !OK {\n\t\tlog.Debugf(\"no cache found for segment: %s, key: %s\", segment.Name(), key)\n\t\treturn false\n\t}\n\n\terr := json.Unmarshal([]byte(data), &segment.writer)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tsegment.Enabled = true\n\ttemplate.Cache.AddSegmentData(segment.Name(), segment.writer)\n\n\tlog.Debug(\"restored segment from cache: \", segment.Name())\n\n\tsegment.restored = true\n\n\treturn true\n}\n\nfunc (segment *Segment) setCache() {\n\tif segment.restored || !segment.hasCache() {\n\t\treturn\n\t}\n\n\t// Never cache pending state to avoid polluting cache with incomplete data\n\tif segment.Pending {\n\t\treturn\n\t}\n\n\tdata, err := json.Marshal(segment.writer)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\t// TODO: check if we can make segmentwriter a generic Type indicator\n\t// that way we can actually get the value straight from cache.Get\n\t// and marchalling is obsolete\n\tkey, store := segment.cacheKeyAndStore()\n\tcache.Set(store, key, string(data), segment.Cache.Duration)\n}\n\nfunc (segment *Segment) cacheKeyAndStore() (string, cache.Store) {\n\tformat := \"segment_cache_%s\"\n\tswitch segment.Cache.Strategy {\n\tcase Session:\n\t\treturn fmt.Sprintf(format, segment.Name()), cache.Session\n\tcase Device:\n\t\treturn fmt.Sprintf(format, segment.Name()), cache.Device\n\tcase Folder:\n\t\tfallthrough\n\tdefault:\n\t\treturn fmt.Sprintf(format, strings.Join([]string{segment.Name(), segment.folderKey()}, \"_\")), cache.Device\n\t}\n}\n\nfunc (segment *Segment) folderKey() string {\n\tkey, ok := segment.writer.CacheKey()\n\tif !ok {\n\t\treturn segment.env.Pwd()\n\t}\n\n\treturn key\n}\n\nfunc (segment *Segment) string() string {\n\t// Use simple pending text if segment is still pending\n\tif segment.Pending {\n\t\tif segment.Placeholder != \"\" {\n\t\t\treturn segment.Placeholder\n\t\t}\n\n\t\treturn \"...\"\n\t}\n\n\tresult := segment.Templates.Resolve(segment.writer, \"\", segment.TemplatesLogic)\n\tif len(result) != 0 {\n\t\treturn result\n\t}\n\n\tif segment.Template == \"\" {\n\t\tsegment.Template = segment.writer.Template()\n\t}\n\n\ttext, err := template.Render(segment.Template, segment.writer)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\treturn text\n}\n\nfunc (segment *Segment) shouldIncludeFolder() bool {\n\tif segment.env == nil {\n\t\treturn true\n\t}\n\n\tcwdIncluded := segment.cwdIncluded()\n\tcwdExcluded := segment.cwdExcluded()\n\n\treturn cwdIncluded && !cwdExcluded\n}\n\nfunc (segment *Segment) cwdIncluded() bool {\n\tif len(segment.IncludeFolders) == 0 {\n\t\treturn true\n\t}\n\n\treturn segment.env.DirMatchesOneOf(segment.env.Pwd(), segment.IncludeFolders)\n}\n\nfunc (segment *Segment) cwdExcluded() bool {\n\treturn segment.env.DirMatchesOneOf(segment.env.Pwd(), segment.ExcludeFolders)\n}\n\nfunc (segment *Segment) evaluateNeeds() {\n\tvalue := segment.Template\n\n\tif len(segment.ForegroundTemplates) != 0 {\n\t\tvalue += strings.Join(segment.ForegroundTemplates, \"\")\n\t}\n\n\tif len(segment.BackgroundTemplates) != 0 {\n\t\tvalue += strings.Join(segment.BackgroundTemplates, \"\")\n\t}\n\n\tif len(segment.Templates) != 0 {\n\t\tvalue += strings.Join(segment.Templates, \"\")\n\t}\n\n\tif !strings.Contains(value, \".Segments.\") {\n\t\treturn\n\t}\n\n\tmatches := regex.FindAllNamedRegexMatch(`\\.Segments\\.(?P<NAME>[a-zA-Z0-9]+)`, value)\n\tfor _, name := range matches {\n\t\tsegmentName := name[\"NAME\"]\n\n\t\tif len(name) == 0 || slices.Contains(segment.Needs, segmentName) {\n\t\t\tcontinue\n\t\t}\n\n\t\tsegment.Needs = append(segment.Needs, segmentName)\n\t}\n}\n\nfunc (segment *Segment) key() any {\n\tif segment.Index > 0 {\n\t\treturn segment.Index - 1\n\t}\n\n\treturn segment.Name()\n}\n"
  },
  {
    "path": "src/config/segment_test.go",
    "content": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments\"\n\n\ttoml \"github.com/pelletier/go-toml/v2\"\n\t\"github.com/stretchr/testify/assert\"\n\t\"go.yaml.in/yaml/v3\"\n)\n\nconst (\n\tcwd = \"Projects/oh-my-posh\"\n)\n\nfunc TestMapSegmentWriterCanMap(t *testing.T) {\n\tsc := &Segment{\n\t\tType: SESSION,\n\t}\n\tenv := new(mock.Environment)\n\terr := sc.MapSegmentWithWriter(env)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, sc.writer)\n}\n\nfunc TestMapSegmentWriterCannotMap(t *testing.T) {\n\tsc := &Segment{\n\t\tType: \"nilwriter\",\n\t}\n\tenv := new(mock.Environment)\n\terr := sc.MapSegmentWithWriter(env)\n\tassert.Error(t, err)\n}\n\nfunc TestParseTestConfig(t *testing.T) {\n\tsegmentJSON :=\n\t\t`\n\t\t{\n\t\t\t\"type\": \"path\",\n\t\t\t\"style\": \"powerline\",\n\t\t\t\"powerline_symbol\": \"\\uE0B0\",\n\t\t\t\"foreground\": \"#ffffff\",\n\t\t\t\"background\": \"#61AFEF\",\n\t\t\t\"options\": {\n\t\t\t\t\"style\": \"folder\"\n\t\t\t},\n\t\t\t\"exclude_folders\": [\n\t\t\t\t\"/super/secret/project\"\n\t\t\t]\n\t\t}\n\t\t`\n\tsegment := &Segment{}\n\terr := json.Unmarshal([]byte(segmentJSON), segment)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseConfigWithOptions(t *testing.T) {\n\tsegmentJSON :=\n\t\t`\n\t\t{\n\t\t\t\"type\": \"path\",\n\t\t\t\"style\": \"powerline\",\n\t\t\t\"options\": {\n\t\t\t\t\"style\": \"folder\"\n\t\t\t}\n\t\t}\n\t\t`\n\tsegment := &Segment{}\n\terr := json.Unmarshal([]byte(segmentJSON), segment)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseYAMLConfigWithProperties(t *testing.T) {\n\tsegmentYAML := `\ntype: path\nstyle: powerline\nproperties:\n  style: folder\n`\n\tsegment := &Segment{}\n\terr := yaml.Unmarshal([]byte(segmentYAML), segment)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseYAMLConfigWithOptions(t *testing.T) {\n\tsegmentYAML := `\ntype: path\nstyle: powerline\noptions:\n  style: folder\n`\n\tsegment := &Segment{}\n\terr := yaml.Unmarshal([]byte(segmentYAML), segment)\n\tassert.NoError(t, err)\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseTOMLConfigWithProperties(t *testing.T) {\n\tsegmentTOML := `\ntype = \"path\"\nstyle = \"powerline\"\n[properties]\nstyle = \"folder\"\n`\n\tsegment := &Segment{}\n\terr := toml.Unmarshal([]byte(segmentTOML), segment)\n\tassert.NoError(t, err)\n\n\t// Migrate properties to options (normally done by Config.migrateSegmentProperties)\n\tsegment.MigratePropertiesToOptions()\n\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseTOMLConfigWithOptions(t *testing.T) {\n\tsegmentTOML := `\ntype = \"path\"\nstyle = \"powerline\"\n[options]\nstyle = \"folder\"\n`\n\tsegment := &Segment{}\n\terr := toml.Unmarshal([]byte(segmentTOML), segment)\n\tassert.NoError(t, err)\n\n\t// Migrate properties to options (should be a no-op since options is set)\n\tsegment.MigratePropertiesToOptions()\n\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestParseTOMLConfigWithBothOptionsAndProperties(t *testing.T) {\n\t// If both are specified, options takes precedence\n\tsegmentTOML := `\ntype = \"path\"\nstyle = \"powerline\"\n[options]\nstyle = \"folder\"\n[properties]\nstyle = \"letter\"\n`\n\tsegment := &Segment{}\n\terr := toml.Unmarshal([]byte(segmentTOML), segment)\n\tassert.NoError(t, err)\n\n\t// Migrate should not overwrite options\n\tsegment.MigratePropertiesToOptions()\n\n\tassert.NotNil(t, segment.Options)\n\tassert.Equal(t, \"folder\", segment.Options.String(\"style\", \"\"))\n}\n\nfunc TestShouldIncludeFolder(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tIncluded bool\n\t\tExcluded bool\n\t\tExpected bool\n\t}{\n\t\t{Case: \"Include\", Included: true, Excluded: false, Expected: true},\n\t\t{Case: \"Exclude\", Included: false, Excluded: true, Expected: false},\n\t\t{Case: \"Include & Exclude\", Included: true, Excluded: true, Expected: false},\n\t\t{Case: \"!Include & !Exclude\", Included: false, Excluded: false, Expected: false},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\t\tenv.On(\"Home\").Return(\"\")\n\t\tenv.On(\"Pwd\").Return(cwd)\n\t\tenv.On(\"DirMatchesOneOf\", cwd, []string{\"Projects/oh-my-posh\"}).Return(tc.Included)\n\t\tenv.On(\"DirMatchesOneOf\", cwd, []string{\"Projects/nope\"}).Return(tc.Excluded)\n\t\tsegment := &Segment{\n\t\t\tIncludeFolders: []string{\"Projects/oh-my-posh\"},\n\t\t\tExcludeFolders: []string{\"Projects/nope\"},\n\t\t\tenv:            env,\n\t\t}\n\t\tgot := segment.shouldIncludeFolder()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGetColors(t *testing.T) {\n\tcases := []struct {\n\t\tCase       string\n\t\tExpected   color.Ansi\n\t\tDefault    color.Ansi\n\t\tRegion     string\n\t\tProfile    string\n\t\tTemplates  []string\n\t\tBackground bool\n\t}{\n\t\t{Case: \"No template - foreground\", Expected: \"color\", Background: false, Default: \"color\"},\n\t\t{Case: \"No template - background\", Expected: \"color\", Background: true, Default: \"color\"},\n\t\t{Case: \"Nil template\", Expected: \"color\", Default: \"color\", Templates: nil},\n\t\t{\n\t\t\tCase:     \"Template - default\",\n\t\t\tExpected: \"color\",\n\t\t\tDefault:  \"color\",\n\t\t\tTemplates: []string{\n\t\t\t\t\"{{if contains \\\"john\\\" .Profile}}color2{{end}}\",\n\t\t\t},\n\t\t\tProfile: \"doe\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Template - override\",\n\t\t\tExpected: \"color2\",\n\t\t\tDefault:  \"color\",\n\t\t\tTemplates: []string{\n\t\t\t\t\"{{if contains \\\"john\\\" .Profile}}color2{{end}}\",\n\t\t\t},\n\t\t\tProfile: \"john\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Template - override multiple\",\n\t\t\tExpected: \"color3\",\n\t\t\tDefault:  \"color\",\n\t\t\tTemplates: []string{\n\t\t\t\t\"{{if contains \\\"doe\\\" .Profile}}color2{{end}}\",\n\t\t\t\t\"{{if contains \\\"john\\\" .Profile}}color3{{end}}\",\n\t\t\t},\n\t\t\tProfile: \"john\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Template - override multiple no match\",\n\t\t\tExpected: \"color\",\n\t\t\tDefault:  \"color\",\n\t\t\tTemplates: []string{\n\t\t\t\t\"{{if contains \\\"doe\\\" .Profile}}color2{{end}}\",\n\t\t\t\t\"{{if contains \\\"philip\\\" .Profile}}color3{{end}}\",\n\t\t\t},\n\t\t\tProfile: \"john\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tsegment := &Segment{\n\t\t\twriter: &segments.Aws{\n\t\t\t\tProfile: tc.Profile,\n\t\t\t\tRegion:  tc.Region,\n\t\t\t},\n\t\t}\n\n\t\tif tc.Background {\n\t\t\tsegment.Background = tc.Default\n\t\t\tsegment.BackgroundTemplates = tc.Templates\n\t\t\tbgColor := segment.ResolveBackground()\n\t\t\tassert.Equal(t, tc.Expected, bgColor, tc.Case)\n\t\t\tcontinue\n\t\t}\n\n\t\tsegment.Foreground = tc.Default\n\t\tsegment.ForegroundTemplates = tc.Templates\n\t\tfgColor := segment.ResolveForeground()\n\t\tassert.Equal(t, tc.Expected, fgColor, tc.Case)\n\t}\n}\n\nfunc TestEvaluateNeeds(t *testing.T) {\n\tcases := []struct {\n\t\tSegment *Segment\n\t\tCase    string\n\t\tNeeds   []string\n\t}{\n\t\t{\n\t\t\tCase: \"No needs\",\n\t\t\tSegment: &Segment{\n\t\t\t\tTemplate: \"foo\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Template needs\",\n\t\t\tSegment: &Segment{\n\t\t\t\tTemplate: \"{{ .Segments.Git.URL }}\",\n\t\t\t},\n\t\t\tNeeds: []string{\"Git\"},\n\t\t},\n\t\t{\n\t\t\tCase: \"Template & Foreground needs\",\n\t\t\tSegment: &Segment{\n\t\t\t\tTemplate:            \"{{ .Segments.Git.URL }}\",\n\t\t\t\tForegroundTemplates: []string{\"foo\", \"{{ .Segments.Os.Icon }}\"},\n\t\t\t},\n\t\t\tNeeds: []string{\"Git\", \"Os\"},\n\t\t},\n\t\t{\n\t\t\tCase: \"Template & Foreground & Background needs\",\n\t\t\tSegment: &Segment{\n\t\t\t\tTemplate:            \"{{ .Segments.Git.URL }}\",\n\t\t\t\tForegroundTemplates: []string{\"foo\", \"{{ .Segments.Os.Icon }}\"},\n\t\t\t\tBackgroundTemplates: []string{\"bar\", \"{{ .Segments.Exit.Icon }}\"},\n\t\t\t},\n\t\t\tNeeds: []string{\"Git\", \"Os\", \"Exit\"},\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\ttc.Segment.evaluateNeeds()\n\t\tassert.Equal(t, tc.Needs, tc.Segment.Needs, tc.Case)\n\t}\n}\n\nfunc TestSegment_NoCachingWhenPending(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(\"pwsh\")\n\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\tenv.On(\"Pwd\").Return(\"/test\")\n\tenv.On(\"Home\").Return(\"/home\")\n\n\tsegment := &Segment{\n\t\tType:     SESSION,\n\t\tPending:  true,\n\t\tTemplate: \"test\",\n\t}\n\n\terr := segment.MapSegmentWithWriter(env)\n\tassert.NoError(t, err)\n\n\t// When Pending=true, setCache should return early without caching\n\t// We can't easily mock cache.Set, but we can verify the method doesn't panic\n\t// and that the behavior differs between Pending=true and Pending=false\n\n\t// With Pending=true, setCache returns early\n\tsegment.Cache = &Cache{Duration: \"5h\"}\n\tsegment.setCache() // Should return early, not attempt to cache\n\n\t// Verify this doesn't panic and segment still works\n\tassert.True(t, segment.Pending, \"Segment should still be pending\")\n\n\t// Now with Pending=false, setCache will attempt to cache\n\tsegment.Pending = false\n\tsegment.restored = false\n\tsegment.setCache() // Should attempt to cache (may fail but shouldn't panic)\n\n\tassert.False(t, segment.Pending, \"Segment should not be pending\")\n}\n"
  },
  {
    "path": "src/config/segment_types.go",
    "content": "package config\n\nimport (\n\t\"encoding/gob\"\n\t\"errors\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// SegmentType the type of segment, for more information, see the constants\ntype SegmentType string\n\n// SegmentWriter is the interface used to define what and if to write to the prompt\ntype SegmentWriter interface {\n\tEnabled() bool\n\tTemplate() string\n\tSetText(text string)\n\tSetIndex(index int)\n\tText() string\n\tInit(props options.Provider, env runtime.Environment)\n\tCacheKey() (string, bool)\n}\n\nfunc init() {\n\tgob.Register(&segments.Angular{})\n\tgob.Register(&segments.Version{})\n\tgob.Register(&segments.Argocd{})\n\tgob.Register(&segments.Aurelia{})\n\tgob.Register(&segments.Aws{})\n\tgob.Register(&segments.Az{})\n\tgob.Register(&segments.Azd{})\n\tgob.Register(&segments.AzFunc{})\n\tgob.Register(&segments.Battery{})\n\tgob.Register(&segments.Bazel{})\n\tgob.Register(&segments.Brewfather{})\n\tgob.Register(&segments.Buf{})\n\tgob.Register(&segments.Bun{})\n\tgob.Register(&segments.CarbonIntensity{})\n\tgob.Register(&segments.Cds{})\n\tgob.Register(&segments.Copilot{})\n\tgob.Register(&segments.Cf{})\n\tgob.Register(&segments.CfTarget{})\n\tgob.Register(&segments.Claude{})\n\tgob.Register(&segments.ClaudeData{})\n\tgob.Register(&segments.Clojure{})\n\tgob.Register(&segments.Cmake{})\n\tgob.Register(&segments.Connection{})\n\tgob.Register(&segments.Crystal{})\n\tgob.Register(&segments.Dart{})\n\tgob.Register(&segments.Deno{})\n\tgob.Register(&segments.Docker{})\n\tgob.Register(&segments.Dotnet{})\n\tgob.Register(&segments.Elixir{})\n\tgob.Register(&segments.Executiontime{})\n\tgob.Register(&segments.Status{})\n\tgob.Register(&segments.Firebase{})\n\tgob.Register(&segments.Flutter{})\n\tgob.Register(&segments.Fortran{})\n\tgob.Register(&segments.Fossil{})\n\tgob.Register(&segments.FossilStatus{})\n\tgob.Register(&segments.Gcp{})\n\tgob.Register(&segments.Git{})\n\tgob.Register(&segments.GitStatus{})\n\tgob.Register(&segments.Rebase{})\n\tgob.Register(&segments.User{})\n\tgob.Register(&segments.Commit{})\n\tgob.Register(&segments.GitVersion{})\n\tgob.Register(&segments.Golang{})\n\tgob.Register(&segments.Haskell{})\n\tgob.Register(&segments.Helm{})\n\tgob.Register(&segments.IPify{})\n\tgob.Register(&segments.Java{})\n\tgob.Register(&segments.HTTP{})\n\tgob.Register(&segments.Jujutsu{})\n\tgob.Register(&segments.JujutsuStatus{})\n\tgob.Register(&segments.Julia{})\n\tgob.Register(&segments.Kotlin{})\n\tgob.Register(&segments.Kubectl{})\n\tgob.Register(&segments.LastFM{})\n\tgob.Register(&segments.Lua{})\n\tgob.Register(&segments.Mercurial{})\n\tgob.Register(&segments.MercurialStatus{})\n\tgob.Register(&segments.Mojo{})\n\tgob.Register(&segments.Mvn{})\n\tgob.Register(&segments.Nba{})\n\tgob.Register(&segments.Nbgv{})\n\tgob.Register(&segments.Nightscout{})\n\tgob.Register(&segments.NixShell{})\n\tgob.Register(&segments.Nim{})\n\tgob.Register(&segments.Node{})\n\tgob.Register(&segments.Npm{})\n\tgob.Register(&segments.Nx{})\n\tgob.Register(&segments.OCaml{})\n\tgob.Register(&segments.Os{})\n\tgob.Register(&segments.Owm{})\n\tgob.Register(&segments.Path{})\n\tgob.Register(&segments.Folders{})\n\tgob.Register(&segments.Perl{})\n\tgob.Register(&segments.Php{})\n\tgob.Register(&segments.Plastic{})\n\tgob.Register(&segments.PlasticStatus{})\n\tgob.Register(&segments.Pnpm{})\n\tgob.Register(&segments.Project{})\n\tgob.Register(&segments.Pulumi{})\n\tgob.Register(&segments.Python{})\n\tgob.Register(&segments.Quasar{})\n\tgob.Register(&segments.Package{})\n\tgob.Register(&segments.R{})\n\tgob.Register(&segments.Ramadan{})\n\tgob.Register(&segments.React{})\n\tgob.Register(&segments.Root{})\n\tgob.Register(&segments.Ruby{})\n\tgob.Register(&segments.Rust{})\n\tgob.Register(&segments.Sapling{})\n\tgob.Register(&segments.SaplingStatus{})\n\tgob.Register(&segments.Session{})\n\tgob.Register(&segments.Shell{})\n\tgob.Register(&segments.Sitecore{})\n\tgob.Register(&segments.Spotify{})\n\tgob.Register(&segments.Status{})\n\tgob.Register(&segments.Strava{})\n\tgob.Register(&segments.Svelte{})\n\tgob.Register(&segments.Svn{})\n\tgob.Register(&segments.SvnStatus{})\n\tgob.Register(&segments.Swift{})\n\tgob.Register(&segments.SystemInfo{})\n\tgob.Register(&segments.TalosCTL{})\n\tgob.Register(&segments.Taskwarrior{})\n\tgob.Register(&segments.Tauri{})\n\tgob.Register(&segments.Terraform{})\n\tgob.Register(&segments.Text{})\n\tgob.Register(&segments.Time{})\n\tgob.Register(&segments.Todoist{})\n\tgob.Register(&segments.UI5Tooling{})\n\tgob.Register(&segments.Umbraco{})\n\tgob.Register(&segments.Unity{})\n\tgob.Register(&segments.Upgrade{})\n\tgob.Register(&segments.UpgradeCache{})\n\tgob.Register(&segments.V{})\n\tgob.Register(&segments.Vala{})\n\tgob.Register(&segments.Wakatime{})\n\tgob.Register(&segments.WinGet{})\n\tgob.Register(&segments.WinGetPackage{})\n\tgob.Register(&segments.WindowsRegistry{})\n\tgob.Register(&segments.Withings{})\n\tgob.Register(&segments.XMake{})\n\tgob.Register(&segments.Yarn{})\n\tgob.Register(&segments.Ytm{})\n\tgob.Register(&segments.Zig{})\n\tgob.Register(&segments.Segment{})\n}\n\nconst (\n\t// Plain writes it without ornaments\n\tPlain SegmentStyle = \"plain\"\n\t// Powerline writes it Powerline style\n\tPowerline SegmentStyle = \"powerline\"\n\t// Accordion writes it Powerline style but collapses the segment when disabled instead of hiding\n\tAccordion SegmentStyle = \"accordion\"\n\t// Diamond writes the prompt shaped with a leading and trailing symbol\n\tDiamond SegmentStyle = \"diamond\"\n\t// ANGULAR writes which angular cli version us currently active\n\tANGULAR SegmentType = \"angular\"\n\t// ARGOCD writes the current argocd context\n\tARGOCD SegmentType = \"argocd\"\n\t// AURELIA writes which aurelia version is currently referenced in package.json\n\tAURELIA SegmentType = \"aurelia\"\n\t// AWS writes the active aws context\n\tAWS SegmentType = \"aws\"\n\t// AZ writes the Azure subscription info we're currently in\n\tAZ SegmentType = \"az\"\n\t// AZD writes the Azure Developer CLI environment info we're current in\n\tAZD SegmentType = \"azd\"\n\t// AZFUNC writes current AZ func version\n\tAZFUNC SegmentType = \"azfunc\"\n\t// BATTERY writes the battery percentage\n\tBATTERY SegmentType = \"battery\"\n\t// BAZEL writes the bazel version\n\tBAZEL SegmentType = \"bazel\"\n\t// Brewfather segment\n\tBREWFATHER SegmentType = \"brewfather\"\n\t// Buf segment writes the active buf version\n\tBUF SegmentType = \"buf\"\n\t// BUN writes the active bun version\n\tBUN SegmentType = \"bun\"\n\t// CARBONINTENSITY writes the actual and forecast carbon intensity in gCO2/kWh\n\tCARBONINTENSITY SegmentType = \"carbonintensity\"\n\t// cds (SAP CAP) version\n\tCDS SegmentType = \"cds\"\n\t// Cloud Foundry segment\n\tCF SegmentType = \"cf\"\n\t// Cloud Foundry logged in target\n\tCFTARGET SegmentType = \"cftarget\"\n\t// CLAUDE writes Claude Code session information\n\tCLAUDE SegmentType = \"claude\"\n\t// CLOJURE writes the active clojure version\n\tCLOJURE SegmentType = \"clojure\"\n\t// CMAKE writes the active cmake version\n\tCMAKE SegmentType = \"cmake\"\n\t// CONNECTION writes a connection's information\n\tCONNECTION SegmentType = \"connection\"\n\t// COPILOT writes GitHub Copilot usage statistics\n\tCOPILOT SegmentType = \"copilot\"\n\t// CRYSTAL writes the active crystal version\n\tCRYSTAL SegmentType = \"crystal\"\n\t// DART writes the active dart version\n\tDART SegmentType = \"dart\"\n\t// DENO writes the active deno version\n\tDENO SegmentType = \"deno\"\n\t// DOCKER writes the docker context\n\tDOCKER SegmentType = \"docker\"\n\t// DOTNET writes which dotnet version is currently active\n\tDOTNET SegmentType = \"dotnet\"\n\t// ELIXIR writes the elixir version\n\tELIXIR SegmentType = \"elixir\"\n\t// EXECUTIONTIME writes the execution time of the last run command\n\tEXECUTIONTIME SegmentType = \"executiontime\"\n\t// EXIT writes the last exit code\n\tEXIT SegmentType = \"exit\"\n\t// FIREBASE writes the active firebase project\n\tFIREBASE SegmentType = \"firebase\"\n\t// FLUTTER writes the flutter version\n\tFLUTTER SegmentType = \"flutter\"\n\t// FORTRAN writes the gfortran version\n\tFORTRAN SegmentType = \"fortran\"\n\t// FOSSIL writes the fossil status\n\tFOSSIL SegmentType = \"fossil\"\n\t// GCP writes the active GCP context\n\tGCP SegmentType = \"gcp\"\n\t// GIT represents the git status and information\n\tGIT SegmentType = \"git\"\n\t// GITVERSION represents the gitversion information\n\tGITVERSION SegmentType = \"gitversion\"\n\t// GOLANG writes which go version is currently active\n\tGOLANG SegmentType = \"go\"\n\t// HASKELL segment\n\tHASKELL SegmentType = \"haskell\"\n\t// HELM segment\n\tHELM SegmentType = \"helm\"\n\t// IPIFY segment\n\tIPIFY SegmentType = \"ipify\"\n\t// JAVA writes the active java version\n\tJAVA SegmentType = \"java\"\n\t// API writes the output of a custom JSON API\n\tHTTP SegmentType = \"http\"\n\t// JUJUTSU writes Jujutsu source control information\n\tJUJUTSU SegmentType = \"jujutsu\"\n\t// JULIA writes which julia version is currently active\n\tJULIA SegmentType = \"julia\"\n\t// KOTLIN writes the active kotlin version\n\tKOTLIN SegmentType = \"kotlin\"\n\t// KUBECTL writes the Kubernetes context we're currently in\n\tKUBECTL SegmentType = \"kubectl\"\n\t// LASTFM writes the lastfm status\n\tLASTFM SegmentType = \"lastfm\"\n\t// LUA writes the active lua version\n\tLUA SegmentType = \"lua\"\n\t// MERCURIAL writes Mercurial source control information\n\tMERCURIAL SegmentType = \"mercurial\"\n\t// MOJO writes the active version of Mojo and the name of the Magic virtual env\n\tMOJO SegmentType = \"mojo\"\n\t// MVN writes the active maven version\n\tMVN SegmentType = \"mvn\"\n\t// NBA writes NBA game data\n\tNBA SegmentType = \"nba\"\n\t// NBGV writes the nbgv version information\n\tNBGV SegmentType = \"nbgv\"\n\t// NIGHTSCOUT is an open source diabetes system\n\tNIGHTSCOUT SegmentType = \"nightscout\"\n\t// NIM writes the active nim version\n\tNIM SegmentType = \"nim\"\n\t// NIXSHELL writes the active nix shell details\n\tNIXSHELL SegmentType = \"nix-shell\"\n\t// NODE writes which node version is currently active\n\tNODE SegmentType = \"node\"\n\t// npm version\n\tNPM SegmentType = \"npm\"\n\t// NX writes which Nx version us currently active\n\tNX SegmentType = \"nx\"\n\t// OCAML writes the active Ocaml version\n\tOCAML SegmentType = \"ocaml\"\n\t// OS write os specific icon\n\tOS SegmentType = \"os\"\n\t// OWM writes the weather coming from openweatherdata\n\tOWM SegmentType = \"owm\"\n\t// PATH represents the current path segment\n\tPATH SegmentType = \"path\"\n\t// PERL writes which perl version is currently active\n\tPERL SegmentType = \"perl\"\n\t// PHP writes which php version is currently active\n\tPHP SegmentType = \"php\"\n\t// PLASTIC represents the plastic scm status and information\n\tPLASTIC SegmentType = \"plastic\"\n\t// pnpm version\n\tPNPM SegmentType = \"pnpm\"\n\t// Project version\n\tPROJECT SegmentType = \"project\"\n\t// PULUMI writes the pulumi user, store and stack\n\tPULUMI SegmentType = \"pulumi\"\n\t// PYTHON writes the virtual env name\n\tPYTHON SegmentType = \"python\"\n\t// QUASAR writes the QUASAR version and context\n\tQUASAR SegmentType = \"quasar\"\n\t// R version\n\tR SegmentType = \"r\"\n\t// RAMADAN displays Sehar and Iftar prayer times during Ramadan\n\tRAMADAN SegmentType = \"ramadan\"\n\t// REACT writes the current react version\n\tREACT SegmentType = \"react\"\n\t// ROOT writes root symbol\n\tROOT SegmentType = \"root\"\n\t// RUBY writes which ruby version is currently active\n\tRUBY SegmentType = \"ruby\"\n\t// RUST writes the cargo version information if cargo.toml is present\n\tRUST SegmentType = \"rust\"\n\t// SAPLING represents the sapling segment\n\tSAPLING SegmentType = \"sapling\"\n\t// SESSION represents the user info segment\n\tSESSION SegmentType = \"session\"\n\t// SHELL writes which shell we're currently in\n\tSHELL SegmentType = \"shell\"\n\t// SITECORE displays the current context for the Sitecore CLI\n\tSITECORE SegmentType = \"sitecore\"\n\t// SPOTIFY writes the SPOTIFY status for Mac\n\tSPOTIFY SegmentType = \"spotify\"\n\t// STATUS writes the last know command status\n\tSTATUS SegmentType = \"status\"\n\t// STRAVA is a sports activity tracker\n\tSTRAVA SegmentType = \"strava\"\n\t// Svelte segment\n\tSVELTE SegmentType = \"svelte\"\n\t// Subversion segment\n\tSVN SegmentType = \"svn\"\n\t// SWIFT writes the active swift version\n\tSWIFT SegmentType = \"swift\"\n\t// SYSTEMINFO writes system information (memory, cpu, load)\n\tSYSTEMINFO SegmentType = \"sysinfo\"\n\t// TALOSCTL writes the talosctl context\n\tTALOSCTL SegmentType = \"talosctl\"\n\t// TASKWARRIOR writes Taskwarrior task counts and context\n\tTASKWARRIOR SegmentType = \"taskwarrior\"\n\t// Tauri Segment\n\tTAURI SegmentType = \"tauri\"\n\t// TERRAFORM writes the terraform workspace we're currently in\n\tTERRAFORM SegmentType = \"terraform\"\n\t// TEXT writes a text\n\tTEXT SegmentType = \"text\"\n\t// TIME writes the current timestamp\n\tTIME SegmentType = \"time\"\n\t// TODOIST segment\n\tTODOIST SegmentType = \"todoist\"\n\t// UI5 Tooling segment\n\tUI5TOOLING SegmentType = \"ui5tooling\"\n\t// UMBRACO writes the Umbraco version if Umbraco is present\n\tUMBRACO SegmentType = \"umbraco\"\n\t// UNITY writes which Unity version is currently active\n\tUNITY SegmentType = \"unity\"\n\t// UPGRADE lets you know if you can upgrade Oh My Posh\n\tUPGRADE SegmentType = \"upgrade\"\n\t// V writes the active vlang version\n\tV SegmentType = \"v\"\n\t// VALA writes the active vala version\n\tVALA SegmentType = \"vala\"\n\t// WAKATIME writes tracked time spend in dev editors\n\tWAKATIME SegmentType = \"wakatime\"\n\t// WINGET writes the number of available WinGet package updates\n\tWINGET SegmentType = \"winget\"\n\t// WINREG queries the Windows registry.\n\tWINREG SegmentType = \"winreg\"\n\t// WITHINGS queries the Withings API.\n\tWITHINGS SegmentType = \"withings\"\n\t// XMAKE write the xmake version if xmake.lua is present\n\tXMAKE SegmentType = \"xmake\"\n\t// yarn version\n\tYARN SegmentType = \"yarn\"\n\t// YTM writes YouTube Music information and status\n\tYTM SegmentType = \"ytm\"\n\t// ZIG writes the active zig version\n\tZIG SegmentType = \"zig\"\n)\n\n// Segments contains all available prompt segment writers.\n// Consumers of the library can also add their own segment writer.\nvar Segments = map[SegmentType]func() SegmentWriter{\n\tANGULAR:         func() SegmentWriter { return &segments.Angular{} },\n\tARGOCD:          func() SegmentWriter { return &segments.Argocd{} },\n\tAURELIA:         func() SegmentWriter { return &segments.Aurelia{} },\n\tAWS:             func() SegmentWriter { return &segments.Aws{} },\n\tAZ:              func() SegmentWriter { return &segments.Az{} },\n\tAZD:             func() SegmentWriter { return &segments.Azd{} },\n\tAZFUNC:          func() SegmentWriter { return &segments.AzFunc{} },\n\tBATTERY:         func() SegmentWriter { return &segments.Battery{} },\n\tBAZEL:           func() SegmentWriter { return &segments.Bazel{} },\n\tBREWFATHER:      func() SegmentWriter { return &segments.Brewfather{} },\n\tBUF:             func() SegmentWriter { return &segments.Buf{} },\n\tBUN:             func() SegmentWriter { return &segments.Bun{} },\n\tCARBONINTENSITY: func() SegmentWriter { return &segments.CarbonIntensity{} },\n\tCDS:             func() SegmentWriter { return &segments.Cds{} },\n\tCF:              func() SegmentWriter { return &segments.Cf{} },\n\tCFTARGET:        func() SegmentWriter { return &segments.CfTarget{} },\n\tCLAUDE:          func() SegmentWriter { return &segments.Claude{} },\n\tCLOJURE:         func() SegmentWriter { return &segments.Clojure{} },\n\tCMAKE:           func() SegmentWriter { return &segments.Cmake{} },\n\tCONNECTION:      func() SegmentWriter { return &segments.Connection{} },\n\tCOPILOT:         func() SegmentWriter { return &segments.Copilot{} },\n\tCRYSTAL:         func() SegmentWriter { return &segments.Crystal{} },\n\tDART:            func() SegmentWriter { return &segments.Dart{} },\n\tDENO:            func() SegmentWriter { return &segments.Deno{} },\n\tDOCKER:          func() SegmentWriter { return &segments.Docker{} },\n\tDOTNET:          func() SegmentWriter { return &segments.Dotnet{} },\n\tELIXIR:          func() SegmentWriter { return &segments.Elixir{} },\n\tEXECUTIONTIME:   func() SegmentWriter { return &segments.Executiontime{} },\n\tEXIT:            func() SegmentWriter { return &segments.Status{} },\n\tFIREBASE:        func() SegmentWriter { return &segments.Firebase{} },\n\tFLUTTER:         func() SegmentWriter { return &segments.Flutter{} },\n\tFORTRAN:         func() SegmentWriter { return &segments.Fortran{} },\n\tFOSSIL:          func() SegmentWriter { return &segments.Fossil{} },\n\tGCP:             func() SegmentWriter { return &segments.Gcp{} },\n\tGIT:             func() SegmentWriter { return &segments.Git{} },\n\tGITVERSION:      func() SegmentWriter { return &segments.GitVersion{} },\n\tGOLANG:          func() SegmentWriter { return &segments.Golang{} },\n\tHASKELL:         func() SegmentWriter { return &segments.Haskell{} },\n\tHELM:            func() SegmentWriter { return &segments.Helm{} },\n\tIPIFY:           func() SegmentWriter { return &segments.IPify{} },\n\tJAVA:            func() SegmentWriter { return &segments.Java{} },\n\tHTTP:            func() SegmentWriter { return &segments.HTTP{} },\n\tJUJUTSU:         func() SegmentWriter { return &segments.Jujutsu{} },\n\tJULIA:           func() SegmentWriter { return &segments.Julia{} },\n\tKOTLIN:          func() SegmentWriter { return &segments.Kotlin{} },\n\tKUBECTL:         func() SegmentWriter { return &segments.Kubectl{} },\n\tLASTFM:          func() SegmentWriter { return &segments.LastFM{} },\n\tLUA:             func() SegmentWriter { return &segments.Lua{} },\n\tMERCURIAL:       func() SegmentWriter { return &segments.Mercurial{} },\n\tMOJO:            func() SegmentWriter { return &segments.Mojo{} },\n\tMVN:             func() SegmentWriter { return &segments.Mvn{} },\n\tNBA:             func() SegmentWriter { return &segments.Nba{} },\n\tNBGV:            func() SegmentWriter { return &segments.Nbgv{} },\n\tNIGHTSCOUT:      func() SegmentWriter { return &segments.Nightscout{} },\n\tNIXSHELL:        func() SegmentWriter { return &segments.NixShell{} },\n\tNIM:             func() SegmentWriter { return &segments.Nim{} },\n\tNODE:            func() SegmentWriter { return &segments.Node{} },\n\tNPM:             func() SegmentWriter { return &segments.Npm{} },\n\tNX:              func() SegmentWriter { return &segments.Nx{} },\n\tOCAML:           func() SegmentWriter { return &segments.OCaml{} },\n\tOS:              func() SegmentWriter { return &segments.Os{} },\n\tOWM:             func() SegmentWriter { return &segments.Owm{} },\n\tPATH:            func() SegmentWriter { return &segments.Path{} },\n\tPERL:            func() SegmentWriter { return &segments.Perl{} },\n\tPHP:             func() SegmentWriter { return &segments.Php{} },\n\tPLASTIC:         func() SegmentWriter { return &segments.Plastic{} },\n\tPNPM:            func() SegmentWriter { return &segments.Pnpm{} },\n\tPROJECT:         func() SegmentWriter { return &segments.Project{} },\n\tPULUMI:          func() SegmentWriter { return &segments.Pulumi{} },\n\tPYTHON:          func() SegmentWriter { return &segments.Python{} },\n\tQUASAR:          func() SegmentWriter { return &segments.Quasar{} },\n\tR:               func() SegmentWriter { return &segments.R{} },\n\tRAMADAN:         func() SegmentWriter { return &segments.Ramadan{} },\n\tREACT:           func() SegmentWriter { return &segments.React{} },\n\tROOT:            func() SegmentWriter { return &segments.Root{} },\n\tRUBY:            func() SegmentWriter { return &segments.Ruby{} },\n\tRUST:            func() SegmentWriter { return &segments.Rust{} },\n\tSAPLING:         func() SegmentWriter { return &segments.Sapling{} },\n\tSESSION:         func() SegmentWriter { return &segments.Session{} },\n\tSHELL:           func() SegmentWriter { return &segments.Shell{} },\n\tSITECORE:        func() SegmentWriter { return &segments.Sitecore{} },\n\tSPOTIFY:         func() SegmentWriter { return &segments.Spotify{} },\n\tSTATUS:          func() SegmentWriter { return &segments.Status{} },\n\tSTRAVA:          func() SegmentWriter { return &segments.Strava{} },\n\tSVELTE:          func() SegmentWriter { return &segments.Svelte{} },\n\tSVN:             func() SegmentWriter { return &segments.Svn{} },\n\tSWIFT:           func() SegmentWriter { return &segments.Swift{} },\n\tSYSTEMINFO:      func() SegmentWriter { return &segments.SystemInfo{} },\n\tTALOSCTL:        func() SegmentWriter { return &segments.TalosCTL{} },\n\tTASKWARRIOR:     func() SegmentWriter { return &segments.Taskwarrior{} },\n\tTAURI:           func() SegmentWriter { return &segments.Tauri{} },\n\tTERRAFORM:       func() SegmentWriter { return &segments.Terraform{} },\n\tTEXT:            func() SegmentWriter { return &segments.Text{} },\n\tTIME:            func() SegmentWriter { return &segments.Time{} },\n\tTODOIST:         func() SegmentWriter { return &segments.Todoist{} },\n\tUI5TOOLING:      func() SegmentWriter { return &segments.UI5Tooling{} },\n\tUMBRACO:         func() SegmentWriter { return &segments.Umbraco{} },\n\tUNITY:           func() SegmentWriter { return &segments.Unity{} },\n\tUPGRADE:         func() SegmentWriter { return &segments.Upgrade{} },\n\tV:               func() SegmentWriter { return &segments.V{} },\n\tVALA:            func() SegmentWriter { return &segments.Vala{} },\n\tWAKATIME:        func() SegmentWriter { return &segments.Wakatime{} },\n\tWINGET:          func() SegmentWriter { return &segments.WinGet{} },\n\tWINREG:          func() SegmentWriter { return &segments.WindowsRegistry{} },\n\tWITHINGS:        func() SegmentWriter { return &segments.Withings{} },\n\tXMAKE:           func() SegmentWriter { return &segments.XMake{} },\n\tYARN:            func() SegmentWriter { return &segments.Yarn{} },\n\tYTM:             func() SegmentWriter { return &segments.Ytm{} },\n\tZIG:             func() SegmentWriter { return &segments.Zig{} },\n}\n\nfunc (segment *Segment) MapSegmentWithWriter(env runtime.Environment) error {\n\tsegment.env = env\n\n\tif segment.Options == nil {\n\t\tsegment.Options = make(options.Map)\n\t}\n\n\tf, ok := Segments[segment.Type]\n\tif !ok {\n\t\treturn errors.New(\"unable to map writer\")\n\t}\n\n\twriter := f()\n\twriter.Init(segment.Options, env)\n\tsegment.writer = writer\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/constants/constants_unix.go",
    "content": "//go:build !windows\n\npackage constants\n\nconst (\n\tDotnetExitCode = 142\n)\n"
  },
  {
    "path": "src/constants/constants_windows.go",
    "content": "package constants\n\nconst (\n\tDotnetExitCode = int(0x80008091)\n)\n"
  },
  {
    "path": "src/dsc/cli.go",
    "content": "package dsc\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tstate string\n)\n\ntype resource interface {\n\tLoad()\n\tSave()\n\tResolve()\n\tToJSON() string\n\tSchema() string\n\tApply(schema string) error\n\tTest(input string) error\n}\n\nfunc Command(r resource) *cobra.Command {\n\tcmd := &cobra.Command{\n\t\tUse:       \"dsc\",\n\t\tShort:     \"Manage Oh My Posh DSC (Desired State Configuration)\",\n\t\tLong:      \"Manage Oh My Posh DSC (Desired State Configuration).\",\n\t\tValidArgs: []string{\"get\", \"set\", \"test\", \"schema\", \"export\"},\n\t\tRun: func(cmd *cobra.Command, args []string) {\n\t\t\tif len(args) == 0 {\n\t\t\t\t_ = cmd.Help()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tenv := &runtime.Terminal{}\n\t\t\tenv.Init(&runtime.Flags{})\n\n\t\t\tcache.Init(os.Getenv(\"POSH_SHELL\"), cache.Persist)\n\n\t\t\tdefer func() {\n\t\t\t\tcache.Close()\n\t\t\t}()\n\n\t\t\tvar err error\n\n\t\t\tswitch args[0] {\n\t\t\tcase \"get\", \"export\":\n\t\t\t\tr.Load()\n\t\t\t\tr.Resolve()\n\t\t\t\tfmt.Print(r.ToJSON())\n\t\t\tcase \"set\":\n\t\t\t\tif state == \"\" {\n\t\t\t\t\terr = newError(\"please provide a state configuration to set\")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tr.Load()\n\t\t\t\terr = r.Apply(state)\n\t\t\tcase \"schema\":\n\t\t\t\tfmt.Print(r.Schema())\n\t\t\tcase \"test\":\n\t\t\t\tif state == \"\" {\n\t\t\t\t\terr = newError(\"please provide a state configuration to test\")\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tr.Load()\n\t\t\t\terr = r.Test(state)\n\t\t\tdefault:\n\t\t\t\t_ = cmd.Help()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif err != nil {\n\t\t\t\tfmt.Println(err.Error())\n\t\t\t\treturn\n\t\t\t}\n\t\t},\n\t}\n\n\tcmd.Flags().StringVar(&state, \"state\", \"\", \"State configuration to set\")\n\treturn cmd\n}\n"
  },
  {
    "path": "src/dsc/error.go",
    "content": "package dsc\n\ntype Error struct {\n\tmessage string\n}\n\nfunc (e *Error) Error() string {\n\treturn `{\n    \"error\": \"` + e.message + `\"\n}`\n}\n\nfunc newError(message string) *Error {\n\treturn &Error{\n\t\tmessage: message,\n\t}\n}\n"
  },
  {
    "path": "src/dsc/resource.go",
    "content": "package dsc\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/invopop/jsonschema\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Resource[T State[T]] struct {\n\tStates []T `json:\"states,omitempty\" jsonschema:\"title=states,description=The different states of the resource\"`\n}\n\ntype State[T any] interface {\n\tEqual(state T) bool\n\tApply() error\n\tResolve() (T, bool)\n}\n\nfunc (resource *Resource[T]) Load() {\n\tstates, ok := cache.Get[[]T](cache.Device, resource.cacheKey())\n\tif !ok {\n\t\tlog.Debug(\"no states found in cache\")\n\t\treturn\n\t}\n\n\tresource.States = states\n}\n\nfunc (resource *Resource[T]) Save() {\n\tcache.Set(cache.Device, resource.cacheKey(), resource.States, cache.INFINITE)\n}\n\nfunc (resource *Resource[T]) Add(item T) {\n\tfor _, existingItem := range resource.States {\n\t\tif existingItem.Equal(item) {\n\t\t\tlog.Debug(\"item already exists\")\n\t\t\treturn\n\t\t}\n\t}\n\n\tlog.Debug(\"adding item\")\n\n\tresource.States = append(resource.States, item)\n}\n\nfunc (resource *Resource[T]) Resolve() {\n\tfor _, item := range resource.States {\n\t\tif resolvedItem, ok := item.Resolve(); ok {\n\t\t\tresource.States = append(resource.States, resolvedItem)\n\t\t}\n\t}\n}\n\nfunc (resource *Resource[T]) Apply(schema string) error {\n\tlog.Debug(\"applying items\")\n\n\terr := json.Unmarshal([]byte(schema), resource)\n\tif err != nil {\n\t\treturn newError(err.Error())\n\t}\n\n\t// TODO: validate if we need to filter out States\n\t// which are already available in the cache (and thus set)\n\n\tfor _, item := range resource.States {\n\t\tif applyErr := item.Apply(); applyErr != nil {\n\t\t\tlog.Error(applyErr)\n\t\t\terr = errors.Join(err, applyErr)\n\t\t}\n\t}\n\n\tlog.Debug(\"items applied\")\n\n\tresource.Save()\n\n\tif err != nil {\n\t\treturn newError(err.Error())\n\t}\n\n\treturn nil\n}\n\nfunc (resource *Resource[T]) Test(_ string) error {\n\treturn newError(\"test functionality not implemented\")\n}\n\nfunc (resource *Resource[T]) Schema() string {\n\treflector := jsonschema.Reflector{\n\t\tExpandedStruct: true,\n\t\tDoNotReference: true,\n\t}\n\n\tschema := reflector.Reflect(resource)\n\tschema.ID = jsonschema.ID(resource.getItemTypeName())\n\tschema.Properties.Delete(\"$schema\")\n\tschemaJSON, _ := json.MarshalIndent(schema, \"\", \"  \")\n\n\treturn string(schemaJSON)\n}\n\nfunc (resource *Resource[T]) getItemTypeName() string {\n\tvar zero T\n\tt := reflect.TypeOf(zero)\n\tif t.Kind() == reflect.Pointer {\n\t\treturn strings.ToLower(t.Elem().Name())\n\t}\n\n\treturn strings.ToLower(t.Name())\n}\n\nfunc (resource *Resource[T]) cacheKey() string {\n\treturn \"DSC_\" + strings.ToUpper(resource.getItemTypeName())\n}\n\nfunc (resource *Resource[T]) ToJSON() string {\n\tvar result bytes.Buffer\n\tjsonEncoder := json.NewEncoder(&result)\n\tjsonEncoder.SetEscapeHTML(false)\n\t_ = jsonEncoder.Encode(resource)\n\treturn result.String()\n}\n"
  },
  {
    "path": "src/generics/convert.go",
    "content": "package generics\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n)\n\ntype Numeric interface {\n\t~int | ~int64 | ~uint64 | ~float64\n}\n\nfunc toNumeric[T Numeric](value any) (T, error) {\n\tswitch v := value.(type) {\n\tcase string:\n\t\tparsed, err := strconv.ParseFloat(v, 64)\n\t\tif err == nil {\n\t\t\treturn T(parsed), nil\n\t\t}\n\t\treturn T(0), err\n\tcase int:\n\t\treturn T(v), nil\n\tcase int64:\n\t\treturn T(v), nil\n\tcase uint64:\n\t\treturn T(v), nil\n\tcase float64:\n\t\treturn T(v), nil\n\tcase bool:\n\t\tif v {\n\t\t\treturn T(1), nil\n\t\t}\n\t\treturn T(0), nil\n\tdefault:\n\t\treturn T(0), errors.New(\"invalid numeric type\")\n\t}\n}\n\nfunc TryParseInt[T ~int | ~int64](value any) (T, error) {\n\treturn toNumeric[T](value)\n}\n\nfunc TryParseFloat[T ~float64](value any) (T, error) {\n\treturn toNumeric[T](value)\n}\n\nfunc ToInt[T ~int | ~int64](value any) T {\n\tresult, err := toNumeric[T](value)\n\tif err != nil {\n\t\treturn T(0)\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "src/generics/pool.go",
    "content": "package generics\n\nimport \"sync\"\n\ntype Pool[T any] struct {\n\tpool sync.Pool\n\tnew  func() T\n}\n\nfunc NewPool[T any](newFunc func() T) *Pool[T] {\n\treturn &Pool[T]{\n\t\tpool: sync.Pool{\n\t\t\tNew: func() any { return newFunc() },\n\t\t},\n\t\tnew: newFunc,\n\t}\n}\n\nfunc (p *Pool[T]) Get() T {\n\treturn p.pool.Get().(T)\n}\n\nfunc (p *Pool[T]) Put(item T) {\n\tp.pool.Put(item)\n}\n"
  },
  {
    "path": "src/generics/slices.go",
    "content": "package generics\n\nimport \"fmt\"\n\n// ParseStringSlice converts any slice to a string slice\nfunc ParseStringSlice(param any) []string {\n\treturn parseSlice(param, func(v any) string { return fmt.Sprint(v) })\n}\n\n// parseSlice converts any slice type to a typed slice using a converter function\nfunc parseSlice[T any](param any, converter func(any) T) []T {\n\tswitch v := param.(type) {\n\tcase []any:\n\t\tif len(v) == 0 {\n\t\t\treturn []T{}\n\t\t}\n\n\t\tresult := make([]T, len(v))\n\t\tfor i, item := range v {\n\t\t\tresult[i] = converter(item)\n\t\t}\n\n\t\treturn result\n\tcase []T:\n\t\treturn v\n\tdefault:\n\t\treturn []T{}\n\t}\n}\n"
  },
  {
    "path": "src/go.mod",
    "content": "module github.com/jandedobbeleer/oh-my-posh/src\n\ngo 1.26.0\n\nrequire (\n\tgithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c\n\tgithub.com/Masterminds/sprig/v3 v3.3.0\n\tgithub.com/alecthomas/assert v1.0.0\n\tgithub.com/alecthomas/colour v0.1.0 // indirect\n\tgithub.com/alecthomas/repr v0.5.2 // indirect\n\tgithub.com/esimov/stackblur-go v1.1.1\n\tgithub.com/fogleman/gg v1.3.0\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/gookit/color v1.6.0\n\tgithub.com/huandu/xstrings v1.5.0 // indirect\n\tgithub.com/mitchellh/copystructure v1.2.0 // indirect\n\tgithub.com/sergi/go-diff v1.4.0 // indirect\n\tgithub.com/stretchr/objx v0.5.3 // indirect\n\tgithub.com/stretchr/testify v1.11.1\n\tgithub.com/wayneashleyberry/terminal-dimensions v1.1.0\n\tgolang.org/x/crypto v0.48.0 // indirect\n\tgolang.org/x/image v0.37.0\n\tgolang.org/x/sys v0.42.0\n\tgolang.org/x/text v0.35.0\n\tgopkg.in/ini.v1 v1.67.1\n)\n\nrequire (\n\tgithub.com/ConradIrwin/font v0.2.1\n\tgithub.com/charmbracelet/bubbles v1.0.0\n\tgithub.com/charmbracelet/bubbletea v1.3.10\n\tgithub.com/charmbracelet/lipgloss v1.1.0\n\tgithub.com/gookit/goutil v0.7.4\n\tgithub.com/hashicorp/hcl/v2 v2.24.0\n\tgithub.com/invopop/jsonschema v0.13.0\n\tgithub.com/mattn/go-runewidth v0.0.21\n\tgithub.com/pelletier/go-toml/v2 v2.2.4\n\tgithub.com/shirou/gopsutil/v4 v4.26.2\n\tgithub.com/spf13/cobra v1.10.2\n\tgithub.com/spf13/pflag v1.0.10\n\tgo.yaml.in/yaml/v3 v3.0.4\n\tgolang.org/x/mod v0.34.0\n)\n\nrequire (\n\tgithub.com/Masterminds/goutils v1.1.1 // indirect\n\tgithub.com/Masterminds/semver/v3 v3.4.0 // indirect\n\tgithub.com/davecgh/go-spew v1.1.1 // indirect\n\tgithub.com/go-ole/go-ole v1.3.0 // indirect\n\tgithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/mitchellh/reflectwalk v1.0.2 // indirect\n\tgithub.com/pmezard/go-difflib v1.0.0 // indirect\n\tgithub.com/spf13/cast v1.10.0 // indirect\n\tgithub.com/tklauser/go-sysconf v0.3.16 // indirect\n\tgithub.com/tklauser/numcpus v0.11.0 // indirect\n\tgithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect\n)\n\nrequire (\n\tdario.cat/mergo v1.0.2 // indirect\n\tdmitri.shuralyov.com/font/woff2 v0.0.0-20180220214647-957792cbbdab // indirect\n\tgithub.com/agext/levenshtein v1.2.3 // indirect\n\tgithub.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect\n\tgithub.com/atotto/clipboard v0.1.4 // indirect\n\tgithub.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect\n\tgithub.com/bahlo/generic-list-go v0.2.0 // indirect\n\tgithub.com/buger/jsonparser v1.1.2 // indirect\n\tgithub.com/charmbracelet/colorprofile v0.4.1 // indirect\n\tgithub.com/charmbracelet/harmonica v0.2.0 // indirect\n\tgithub.com/charmbracelet/x/ansi v0.11.6 // indirect\n\tgithub.com/charmbracelet/x/cellbuf v0.0.15 // indirect\n\tgithub.com/charmbracelet/x/term v0.2.2 // indirect\n\tgithub.com/clipperhouse/displaywidth v0.10.0 // indirect\n\tgithub.com/clipperhouse/uax29/v2 v2.6.0 // indirect\n\tgithub.com/dsnet/compress v0.0.1 // indirect\n\tgithub.com/ebitengine/purego v0.10.0 // indirect\n\tgithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect\n\tgithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect\n\tgithub.com/google/go-cmp v0.7.0 // indirect\n\tgithub.com/inconshreveable/mousetrap v1.1.0 // indirect\n\tgithub.com/lucasb-eyer/go-colorful v1.3.0 // indirect\n\tgithub.com/mailru/easyjson v0.9.1 // indirect\n\tgithub.com/mattn/go-localereader v0.0.1 // indirect\n\tgithub.com/mitchellh/go-wordwrap v1.0.1 // indirect\n\tgithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect\n\tgithub.com/muesli/cancelreader v0.2.2 // indirect\n\tgithub.com/muesli/termenv v0.16.0 // indirect\n\tgithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect\n\tgithub.com/rivo/uniseg v0.4.7 // indirect\n\tgithub.com/sahilm/fuzzy v0.1.1 // indirect\n\tgithub.com/shopspring/decimal v1.4.0 // indirect\n\tgithub.com/wk8/go-ordered-map/v2 v2.1.8 // indirect\n\tgithub.com/yusufpapurcu/wmi v1.2.4 // indirect\n\tgithub.com/zclconf/go-cty v1.17.0 // indirect\n\tgolang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tgolang.org/x/tools v0.42.0 // indirect\n\tgopkg.in/yaml.v3 v3.0.1 // indirect\n)\n\nreplace github.com/atotto/clipboard v0.1.4 => github.com/jandedobbeleer/clipboard v0.1.4-1\n"
  },
  {
    "path": "src/go.sum",
    "content": "dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=\ndario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=\ndmitri.shuralyov.com/font/woff2 v0.0.0-20180220214647-957792cbbdab h1:Ew70NL+wL6v9looOiJJthlqA41VzoJS+q9AyjHJe6/g=\ndmitri.shuralyov.com/font/woff2 v0.0.0-20180220214647-957792cbbdab/go.mod h1:FvHgTMJanm43G7B3MVSjS/jim5ytVqAJNAOpRhnuHJc=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=\ngithub.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=\ngithub.com/ConradIrwin/font v0.2.1 h1:D4tWi7zyRAdVKOtOys5960HnAAfUSRx/syaf+J9JqlI=\ngithub.com/ConradIrwin/font v0.2.1/go.mod h1:krTLO7JWu6g8RMxG8sl+T1Hf8W93XQacBKJmqFZ2MFY=\ngithub.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=\ngithub.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=\ngithub.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=\ngithub.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=\ngithub.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=\ngithub.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=\ngithub.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=\ngithub.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=\ngithub.com/alecthomas/assert v1.0.0 h1:3XmGh/PSuLzDbK3W2gUbRXwgW5lqPkuqvRgeQ30FI5o=\ngithub.com/alecthomas/assert v1.0.0/go.mod h1:va/d2JC+M7F6s+80kl/R3G7FUiW6JzUO+hPhLyJ36ZY=\ngithub.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=\ngithub.com/alecthomas/colour v0.1.0/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=\ngithub.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=\ngithub.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY=\ngithub.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=\ngithub.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=\ngithub.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=\ngithub.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=\ngithub.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=\ngithub.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=\ngithub.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk=\ngithub.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=\ngithub.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=\ngithub.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E=\ngithub.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=\ngithub.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=\ngithub.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=\ngithub.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=\ngithub.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=\ngithub.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=\ngithub.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=\ngithub.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=\ngithub.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=\ngithub.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=\ngithub.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=\ngithub.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=\ngithub.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=\ngithub.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=\ngithub.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=\ngithub.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=\ngithub.com/clipperhouse/displaywidth v0.10.0 h1:GhBG8WuerxjFQQYeuZAeVTuyxuX+UraiZGD4HJQ3Y8g=\ngithub.com/clipperhouse/displaywidth v0.10.0/go.mod h1:XqJajYsaiEwkxOj4bowCTMcT1SgvHo9flfF3jQasdbs=\ngithub.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=\ngithub.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=\ngithub.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=\ngithub.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=\ngithub.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU=\ngithub.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=\ngithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=\ngithub.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=\ngithub.com/esimov/stackblur-go v1.1.1 h1:jZhuCbyFBp34SxkMwCuuNQ+d42w+CE/WOlcJLOlPEag=\ngithub.com/esimov/stackblur-go v1.1.1/go.mod h1:m0T0MjHYbo4Lib/R33XDUMbLBwyGf1/K48ZdqtXUYDA=\ngithub.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=\ngithub.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=\ngithub.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=\ngithub.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=\ngithub.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=\ngithub.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=\ngithub.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=\ngithub.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/gookit/assert v0.1.1 h1:lh3GcawXe/p+cU7ESTZ5Ui3Sm/x8JWpIis4/1aF0mY0=\ngithub.com/gookit/assert v0.1.1/go.mod h1:jS5bmIVQZTIwk42uXl4lyj4iaaxx32tqH16CFj0VX2E=\ngithub.com/gookit/color v1.6.0 h1:JjJXBTk1ETNyqyilJhkTXJYYigHG24TM9Xa2M1xAhRA=\ngithub.com/gookit/color v1.6.0/go.mod h1:9ACFc7/1IpHGBW8RwuDm/0YEnhg3dwwXpoMsmtyHfjs=\ngithub.com/gookit/goutil v0.7.4 h1:OWgUngToNz+bPlX5aP+EMG31DraEU63uvKMwwT3vseM=\ngithub.com/gookit/goutil v0.7.4/go.mod h1:vJS9HXctYTCLtCsZot5L5xF+O1oR17cDYO9R0HxBmnU=\ngithub.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE=\ngithub.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM=\ngithub.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=\ngithub.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=\ngithub.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=\ngithub.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=\ngithub.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=\ngithub.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=\ngithub.com/jandedobbeleer/clipboard v0.1.4-1 h1:rJehm5W0a3hvjcxyB3snqLBV4yvMBBc12JyMP7ngNQw=\ngithub.com/jandedobbeleer/clipboard v0.1.4-1/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=\ngithub.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=\ngithub.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=\ngithub.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=\ngithub.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=\ngithub.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=\ngithub.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=\ngithub.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=\ngithub.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=\ngithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=\ngithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=\ngithub.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=\ngithub.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=\ngithub.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=\ngithub.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=\ngithub.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=\ngithub.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=\ngithub.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=\ngithub.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=\ngithub.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=\ngithub.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=\ngithub.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=\ngithub.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=\ngithub.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=\ngithub.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=\ngithub.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=\ngithub.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=\ngithub.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=\ngithub.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=\ngithub.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=\ngithub.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=\ngithub.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=\ngithub.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=\ngithub.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=\ngithub.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=\ngithub.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=\ngithub.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=\ngithub.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=\ngithub.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=\ngithub.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=\ngithub.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=\ngithub.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d h1:lvCTyBbr36+tqMccdGMwuEU+hjux/zL6xSmf5S9ITaA=\ngithub.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=\ngithub.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=\ngithub.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=\ngithub.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=\ngithub.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=\ngithub.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=\ngithub.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=\ngithub.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=\ngithub.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=\ngithub.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=\ngithub.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=\ngithub.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=\ngithub.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=\ngithub.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=\ngithub.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=\ngithub.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=\ngithub.com/wayneashleyberry/terminal-dimensions v1.1.0 h1:EB7cIzBdsOzAgmhTUtTTQXBByuPheP/Zv1zL2BRPY6g=\ngithub.com/wayneashleyberry/terminal-dimensions v1.1.0/go.mod h1:2lc/0eWCObmhRczn2SdGSQtgBooLUzIotkkEGXqghyg=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=\ngithub.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=\ngithub.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=\ngithub.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=\ngithub.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngithub.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0=\ngithub.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=\ngithub.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=\ngo.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=\ngo.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=\ngolang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=\ngolang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=\ngolang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=\ngolang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=\ngolang.org/x/image v0.37.0 h1:ZiRjArKI8GwxZOoEtUfhrBtaCN+4b/7709dlT6SSnQA=\ngolang.org/x/image v0.37.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=\ngolang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=\ngolang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=\ngolang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=\ngopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "src/log/log.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n)\n\nvar (\n\tenabled bool\n\traw     bool\n\n\tlog strings.Builder\n)\n\nfunc Enable(plain bool) {\n\tenabled = true\n\traw = plain\n\n\tDebugf(\"logging enabled, raw mode: %t\", plain)\n}\n\nfunc Trace(start time.Time, args ...string) {\n\tif !enabled {\n\t\treturn\n\t}\n\n\telapsed := time.Since(start)\n\tfn, _ := funcSpec()\n\n\t// Color-code elapsed time based on duration\n\tvar coloredElapsed Text\n\tms := elapsed.Milliseconds()\n\n\tswitch {\n\tcase ms < 1:\n\t\tcoloredElapsed = Text(elapsed.String()).Green().Plain()\n\tcase ms >= 1 && ms < 10:\n\t\tcoloredElapsed = Text(elapsed.String()).Yellow().Plain()\n\tcase ms >= 10 && ms < 100:\n\t\tcoloredElapsed = Text(elapsed.String()).Orange().Plain()\n\tdefault: // >= 100ms\n\t\tcoloredElapsed = Text(elapsed.String()).Red().Plain()\n\t}\n\n\theader := fmt.Sprintf(\"%s(%s) - %s\", fn, strings.Join(args, \" \"), coloredElapsed)\n\n\tprintLn(trace, header)\n}\n\nfunc Debug(message ...string) {\n\tif !enabled {\n\t\treturn\n\t}\n\n\tfn, line := funcSpec()\n\theader := fmt.Sprintf(\"%s:%d\", fn, line)\n\n\tprintLn(debug, header, strings.Join(message, \" \"))\n}\n\nfunc Debugf(format string, args ...any) {\n\tif !enabled {\n\t\treturn\n\t}\n\n\tmessage := fmt.Sprintf(format, args...)\n\tDebug(message)\n}\n\nfunc Error(err error) {\n\tif !enabled {\n\t\treturn\n\t}\n\tfn, line := funcSpec()\n\theader := fmt.Sprintf(\"%s:%d\", fn, line)\n\n\tprintLn(bug, header, err.Error())\n}\n\nfunc Errorf(format string, args ...any) {\n\tif !enabled {\n\t\treturn\n\t}\n\n\tError(fmt.Errorf(format, args...))\n}\n\nfunc String() string {\n\treturn log.String()\n}\n\nfunc funcSpec() (string, int) {\n\tpcs := make([]uintptr, 4)\n\tn := runtime.Callers(3, pcs)\n\tif n == 0 {\n\t\treturn \"\", 0\n\t}\n\n\tframes := runtime.CallersFrames(pcs[:n])\n\tvar frame runtime.Frame\n\tmore := true\n\n\t// Loop through frames until we're out of log.go\n\tfor more {\n\t\tframe, more = frames.Next()\n\t\tif strings.Contains(frame.File, \"log.go\") {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Found first non-log.go frame\n\t\tfn := frame.Function\n\t\tfn = fn[strings.LastIndex(fn, \".\")+1:]\n\t\tfile := filepath.Base(frame.File)\n\n\t\tif strings.HasPrefix(fn, \"func\") {\n\t\t\treturn file, frame.Line\n\t\t}\n\n\t\treturn fmt.Sprintf(\"%s:%s\", file, fn), frame.Line\n\t}\n\n\treturn \"\", 0\n}\n"
  },
  {
    "path": "src/log/print.go",
    "content": "package log\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n)\n\ntype logType byte\n\nconst (\n\tdebug logType = 1 << iota\n\tbug\n\ttrace\n)\n\ntype Text string\n\nfunc (t Text) Green() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[38;2;191;207;240m\" + t\n}\n\nfunc (t Text) Red() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[38;2;253;122;140m\" + t\n}\n\nfunc (t Text) Purple() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[38;2;204;137;214m\" + t\n}\n\nfunc (t Text) Yellow() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[38;2;156;231;201m\" + t\n}\n\nfunc (t Text) Orange() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[38;2;253;184;109m\" + t\n}\n\nfunc (t Text) Bold() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn \"\\x1b[1m\" + t\n}\n\nfunc (t Text) Plain() Text {\n\tif raw {\n\t\treturn t\n\t}\n\treturn t + \"\\033[0m\"\n}\n\nfunc (t Text) String() string {\n\treturn string(t)\n}\n\nfunc printLn(lt logType, args ...string) {\n\tif len(args) == 0 {\n\t\treturn\n\t}\n\n\tvar str Text\n\tswitch lt {\n\tcase debug:\n\t\tstr = Text(\"[DEBUG] \").Green()\n\tcase bug:\n\t\tstr = Text(\"[ERROR] \").Red()\n\tcase trace:\n\t\tstr = Text(\"[TRACE] \").Purple()\n\t}\n\n\t// timestamp 156, 231, 201\n\tstr += Text(time.Now().Format(\"15:04:05.000\") + \" \").Yellow().Plain()\n\tstr += Text(args[0])\n\tstr += parseArgs(args...)\n\tlog.WriteString(str.String())\n}\n\nfunc parseArgs(args ...string) Text {\n\tif len(args) == 1 {\n\t\treturn \"\\n\"\n\t}\n\n\t// display empty return values as NO DATA\n\tif args[1] == \"\" {\n\t\ttext := Text(\" \\u2192\").Yellow()\n\t\ttext += Text(\" NO DATA\\n\").Red().Plain()\n\t\treturn text\n\t}\n\n\t// print a single line for single output\n\tsplitted := strings.Split(args[1], \"\\n\")\n\tif len(splitted) == 1 {\n\t\ttext := Text(\" \\u2192\").Yellow().Plain()\n\t\treturn Text(fmt.Sprintf(\"%s %s\\n\", text, args[1]))\n\t}\n\n\t// indent multiline output with 4 spaces\n\tvar str Text\n\tstr += Text(\" \\u2193\\n\").Yellow().Plain()\n\tfor _, line := range splitted {\n\t\tstr += Text(fmt.Sprintf(\"    %s\\n\", line))\n\t}\n\treturn str\n}\n"
  },
  {
    "path": "src/main.go",
    "content": "package main\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli\"\n)\n\nfunc main() {\n\tcli.Execute()\n}\n"
  },
  {
    "path": "src/main_test.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/prompt\"\n)\n\nfunc BenchmarkInit(b *testing.B) {\n\tcmd := cli.RootCmd\n\t// needs to be a non-existing file as we panic otherwise\n\tcmd.SetArgs([]string{\"init\", \"fish\", \"--print\", \"--silent\"})\n\tout := bytes.NewBufferString(\"\")\n\tcmd.SetOut(out)\n\n\tfor b.Loop() {\n\t\t_ = cmd.Execute()\n\t}\n}\n\nfunc BenchmarkPrimary(b *testing.B) {\n\tcmd := cli.RootCmd\n\t// needs to be a non-existing file as we panic otherwise\n\tcmd.SetArgs([]string{\"print\", prompt.PRIMARY, \"--pwd\", \"/Users/jan/Code/oh-my-posh/src\", \"--shell\", \"fish\", \"--silent\"})\n\tout := bytes.NewBufferString(\"\")\n\tcmd.SetOut(out)\n\n\tfor b.Loop() {\n\t\t_ = cmd.Execute()\n\t}\n\n\tfmt.Println(\"\")\n}\n"
  },
  {
    "path": "src/maps/concurrent.go",
    "content": "package maps\n\nimport (\n\t\"fmt\"\n\t\"sync\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc NewConcurrent[V any]() *Concurrent[V] {\n\treturn &Concurrent[V]{}\n}\n\n// Concurrent is a generic type-safe concurrent map\ntype Concurrent[V any] struct {\n\tm sync.Map\n}\n\nfunc (cm *Concurrent[V]) Set(key string, value V) {\n\tcm.m.Store(key, value)\n}\n\nfunc (cm *Concurrent[V]) Get(key string) (V, bool) {\n\tval, ok := cm.m.Load(key)\n\tif !ok {\n\t\tvar zero V\n\t\treturn zero, false\n\t}\n\n\treturn val.(V), true\n}\n\nfunc (cm *Concurrent[V]) MustGet(key string) V {\n\tval, ok := cm.m.Load(key)\n\tif !ok {\n\t\tlog.Error(fmt.Errorf(\"key %s not found\", key))\n\t\tvar zero V\n\t\treturn zero\n\t}\n\n\treturn val.(V)\n}\n\nfunc (cm *Concurrent[V]) Delete(key string) {\n\tcm.m.Delete(key)\n}\n\nfunc (cm *Concurrent[V]) Contains(key string) bool {\n\t_, ok := cm.m.Load(key)\n\treturn ok\n}\n\nfunc (cm *Concurrent[V]) ToSimple() Simple[V] {\n\tresult := make(Simple[V])\n\n\tcm.m.Range(func(key, value any) bool {\n\t\tif value == nil {\n\t\t\treturn true\n\t\t}\n\t\tresult[key.(string)] = value.(V)\n\t\treturn true\n\t})\n\n\treturn result\n}\n"
  },
  {
    "path": "src/maps/config.go",
    "content": "package maps\n\nimport (\n\t\"encoding/gob\"\n)\n\nfunc init() {\n\tgob.Register(&Config{})\n\tgob.Register(&Map{})\n}\n\ntype Config struct {\n\tUserName  *Map `json:\"user_name,omitempty\" toml:\"user_name,omitempty\" yaml:\"user_name,omitempty\"`\n\tHostName  *Map `json:\"host_name,omitempty\" toml:\"host_name,omitempty\" yaml:\"host_name,omitempty\"`\n\tShellName *Map `json:\"shell_name,omitempty\" toml:\"shell_name,omitempty\" yaml:\"shell_name,omitempty\"`\n}\n\nfunc (c *Config) GetUserName(key string) string {\n\tif c == nil || c.UserName == nil {\n\t\treturn key\n\t}\n\n\treturn c.UserName.Get(key)\n}\n\nfunc (c *Config) GetHostName(key string) string {\n\tif c == nil || c.HostName == nil {\n\t\treturn key\n\t}\n\n\treturn c.HostName.Get(key)\n}\n\nfunc (c *Config) GetShellName(key string) string {\n\tif c == nil || c.ShellName == nil {\n\t\treturn key\n\t}\n\n\treturn c.ShellName.Get(key)\n}\n\ntype Map map[string]string\n\nfunc (m *Map) Get(key string) string {\n\tif m == nil {\n\t\treturn key\n\t}\n\n\tif value, ok := (*m)[key]; ok {\n\t\treturn value\n\t}\n\n\treturn key\n}\n"
  },
  {
    "path": "src/maps/simple.go",
    "content": "package maps\n\n// Simple is a generic map type that can be specialized for different value types\ntype Simple[V any] map[string]V\n\nfunc (m Simple[V]) ToConcurrent() *Concurrent[V] {\n\tcm := NewConcurrent[V]()\n\tfor k, v := range m {\n\t\tcm.Set(k, v)\n\t}\n\n\treturn cm\n}\n"
  },
  {
    "path": "src/metadata.json",
    "content": "{\n  \"Endpoint\": \"https://weu.codesigning.azure.net\",\n  \"CodeSigningAccountName\": \"oh-my-posh\",\n  \"CertificateProfileName\": \"oh-my-posh\",\n  \"ExcludeCredentials\": [\n    \"AzureCliCredential\",\n    \"AzurePowerShellCredential\",\n    \"ManagedIdentityCredential\",\n    \"SharedTokenCacheCredential\",\n    \"VisualStudioCredential\",\n    \"VisualStudioCodeCredential\",\n    \"InteractiveBrowserCredential\"\n  ]\n}\n"
  },
  {
    "path": "src/prompt/debug.go",
    "content": "package prompt\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\n// debug will loop through your config file and output the timings for each segments\nfunc (e *Engine) PrintDebug(startTime time.Time, version string) string {\n\te.write(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Version:\").Green().Bold().Plain(), version))\n\tsh := e.Env.Shell()\n\tshellVersion := e.Env.Getenv(\"POSH_SHELL_VERSION\")\n\tif len(shellVersion) != 0 {\n\t\tsh += fmt.Sprintf(\" (%s)\", shellVersion)\n\t}\n\te.write(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Shell:\").Green().Bold().Plain(), sh))\n\n\t// console title timing\n\ttitleStartTime := time.Now()\n\tlog.Debug(\"segment: Title\")\n\tconsoleTitle := &config.Segment{\n\t\tAlias:      \"ConsoleTitle\",\n\t\tNameLength: 12,\n\t\tEnabled:    len(e.Config.ConsoleTitleTemplate) > 0,\n\t\tDuration:   time.Since(titleStartTime),\n\t\tType:       config.TEXT,\n\t}\n\t_ = consoleTitle.MapSegmentWithWriter(e.Env)\n\tconsoleTitle.SetText(e.getTitleTemplateText())\n\n\tlargestSegmentNameLength := consoleTitle.NameLength\n\n\t// render prompt\n\te.write(log.Text(\"\\nPrompt:\\n\\n\").Green().Bold().Plain().String())\n\te.write(e.Primary())\n\n\te.write(log.Text(\"\\n\\nSegments:\\n\\n\").Green().Bold().Plain().String())\n\n\tvar segments []*config.Segment\n\tsegments = append(segments, consoleTitle)\n\n\tfor _, block := range e.Config.Blocks {\n\t\tfor _, segment := range block.Segments {\n\t\t\tsegments = append(segments, segment)\n\t\t\tif segment.NameLength > largestSegmentNameLength {\n\t\t\t\tlargestSegmentNameLength = segment.NameLength\n\t\t\t}\n\t\t}\n\t}\n\n\t// 22 is the color for false/true and 7 is the reset color\n\tlargestSegmentNameLength += 22 + 7\n\tfor _, segment := range segments {\n\t\tduration := segment.Duration.Milliseconds()\n\t\tvar active log.Text\n\t\tif segment.Enabled {\n\t\t\tactive = log.Text(\"true\").Yellow()\n\t\t} else {\n\t\t\tactive = log.Text(\"false\").Purple()\n\t\t}\n\t\tsegmentName := fmt.Sprintf(\"%s(%s)\", segment.Name(), active.Plain())\n\t\te.write(fmt.Sprintf(\"%-*s - %3d ms\\n\", largestSegmentNameLength, segmentName, duration))\n\t}\n\n\te.write(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Run duration:\").Green().Bold().Plain(), time.Since(startTime)))\n\te.write(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Cache path:\").Green().Bold().Plain(), cache.Path()))\n\n\tcfg := e.Config.Source\n\tif cfg == \"\" {\n\t\tcfg = \"no --config set, using default built-in configuration\"\n\t}\n\n\te.write(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Config path:\").Green().Bold().Plain(), cfg))\n\n\te.write(log.Text(\"\\nLogs:\\n\\n\").Green().Bold().Plain().String())\n\te.write(e.Env.Logs())\n\treturn e.string()\n}\n"
  },
  {
    "path": "src/prompt/engine.go",
    "content": "package prompt\n\nimport (\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\nvar cycle *color.Cycle = &color.Cycle{}\n\ntype Engine struct {\n\tEnv                   runtime.Environment\n\tstreamingResults      chan *config.Segment\n\tConfig                *config.Config\n\tactiveSegment         *config.Segment\n\tpreviousActiveSegment *config.Segment\n\tpendingSegments       sync.Map\n\trprompt               string\n\tOverflow              config.Overflow\n\tprompt                strings.Builder\n\tallBlocks             []*config.Block\n\tcurrentLineLength     int\n\tPadding               int\n\trpromptLength         int\n\tPlain                 bool\n\tforceRender           bool\n}\n\nconst (\n\tPRIMARY   = \"primary\"\n\tTRANSIENT = \"transient\"\n\tDEBUG     = \"debug\"\n\tSECONDARY = \"secondary\"\n\tRIGHT     = \"right\"\n\tTOOLTIP   = \"tooltip\"\n\tVALID     = \"valid\"\n\tERROR     = \"error\"\n\tPREVIEW   = \"preview\"\n)\n\nfunc (e *Engine) write(txt string) {\n\t// Grow capacity proactively if needed\n\tif e.prompt.Cap() < e.prompt.Len()+len(txt) {\n\t\te.prompt.Grow(len(txt) * 2) // Grow by double the needed size to reduce future allocations\n\t}\n\te.prompt.WriteString(txt)\n}\n\nfunc (e *Engine) string() string {\n\ttxt := e.prompt.String()\n\te.prompt.Reset()\n\treturn txt\n}\n\nfunc (e *Engine) canWriteRightBlock(length int, rprompt bool) (int, bool) {\n\tif rprompt && (e.rprompt == \"\") {\n\t\treturn 0, false\n\t}\n\n\tconsoleWidth, err := e.Env.TerminalWidth()\n\tif err != nil || consoleWidth == 0 {\n\t\treturn 0, false\n\t}\n\n\tavailableSpace := consoleWidth - e.currentLineLength\n\n\t// spanning multiple lines\n\tif availableSpace < 0 {\n\t\toverflow := e.currentLineLength % consoleWidth\n\t\tavailableSpace = consoleWidth - overflow\n\t}\n\n\tavailableSpace -= length\n\n\tpromptBreathingRoom := 5\n\tif rprompt {\n\t\tpromptBreathingRoom = 30\n\t}\n\n\tcanWrite := availableSpace >= promptBreathingRoom\n\n\t// reset the available space when we can't write so we can fill the line\n\tif !canWrite {\n\t\tavailableSpace = consoleWidth - length\n\t}\n\n\treturn availableSpace, canWrite\n}\n\nfunc (e *Engine) pwd() {\n\t// only print when relevant\n\tif e.Config.PWD == \"\" {\n\t\treturn\n\t}\n\n\t// only print when supported\n\tsh := e.Env.Shell()\n\tif sh == shell.ELVISH || sh == shell.XONSH {\n\t\treturn\n\t}\n\n\tpwd := e.Env.Pwd()\n\tif e.Env.IsCygwin() {\n\t\tpwd = strings.ReplaceAll(pwd, `\\`, `/`)\n\t}\n\n\t// Allow template logic to define when to enable the PWD (when supported)\n\tpwdType, err := template.Render(e.Config.PWD, nil)\n\tif err != nil || pwdType == \"\" {\n\t\treturn\n\t}\n\n\t// Convert to Windows path when in WSL\n\tif e.Env.IsWsl() {\n\t\tpwd = e.Env.ConvertToWindowsPath(pwd)\n\t}\n\n\tuser := e.Env.User()\n\thost, _ := e.Env.Host()\n\te.write(terminal.Pwd(pwdType, user, host, pwd))\n}\n\nfunc (e *Engine) getNewline() string {\n\tnewline := \"\\n\"\n\n\tif e.Plain || e.Env.Flags().Debug {\n\t\treturn newline\n\t}\n\n\t// Warp terminal will remove a newline character ('\\n') from the prompt, so we hack it in.\n\tif e.isWarp() {\n\t\treturn terminal.LineBreak()\n\t}\n\n\treturn newline\n}\n\nfunc (e *Engine) writeNewline() {\n\tdefer func() {\n\t\te.currentLineLength = 0\n\t}()\n\n\te.write(e.getNewline())\n}\n\nfunc (e *Engine) isWarp() bool {\n\treturn terminal.Program == terminal.Warp\n}\n\nfunc (e *Engine) isIterm() bool {\n\treturn terminal.Program == terminal.ITerm\n}\n\nfunc (e *Engine) shouldFill(filler string, padLength int) (string, bool) {\n\tif filler == \"\" {\n\t\tlog.Debug(\"no filler specified\")\n\t\treturn \"\", false\n\t}\n\n\te.Padding = padLength\n\n\tdefer func() {\n\t\te.Padding = 0\n\t}()\n\n\tvar err error\n\tif filler, err = template.Render(filler, e); err != nil {\n\t\treturn \"\", false\n\t}\n\n\t// allow for easy color overrides and templates\n\tterminal.SetColors(\"default\", \"default\")\n\tterminal.Write(\"\", \"\", filler)\n\tfiller, lenFiller := terminal.String()\n\tif lenFiller == 0 {\n\t\tlog.Debug(\"filler has no length\")\n\t\treturn \"\", false\n\t}\n\n\trepeat := padLength / lenFiller\n\tunfilled := padLength % lenFiller\n\ttxt := strings.Repeat(filler, repeat) + strings.Repeat(\" \", unfilled)\n\tlog.Debug(\"filling with\", txt)\n\treturn txt, true\n}\n\nfunc (e *Engine) getTitleTemplateText() string {\n\tif txt, err := template.Render(e.Config.ConsoleTitleTemplate, nil); err == nil {\n\t\treturn txt\n\t}\n\n\treturn \"\"\n}\n\nfunc (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {\n\tblockText, length := e.writeBlockSegments(block)\n\n\t// do not print anything when we don't have any text unless forced\n\tif !block.Force && length == 0 {\n\t\treturn false\n\t}\n\n\treturn e.writeBlock(block, blockText, length, cancelNewline)\n}\n\n// writeBlock handles the common logic for writing a block to the prompt\nfunc (e *Engine) writeBlock(block *config.Block, blockText string, length int, cancelNewline bool) bool {\n\tdefer func() {\n\t\te.applyPowerShellBleedPatch()\n\t}()\n\n\t// do not print a newline to avoid a leading space\n\t// when we're printing the first primary prompt in\n\t// the shell\n\tif block.Newline && !cancelNewline {\n\t\te.writeNewline()\n\t}\n\n\tswitch block.Type {\n\tcase config.Prompt:\n\t\tif block.Alignment == config.Left {\n\t\t\te.currentLineLength += length\n\t\t\te.write(blockText)\n\t\t\treturn true\n\t\t}\n\n\t\tif block.Alignment != config.Right {\n\t\t\treturn false\n\t\t}\n\n\t\tspace, OK := e.canWriteRightBlock(length, false)\n\n\t\t// we can't print the right block as there's not enough room available\n\t\tif !OK {\n\t\t\te.Overflow = block.Overflow\n\n\t\t\tswitch e.Overflow {\n\t\t\tcase config.Break:\n\t\t\t\te.writeNewline()\n\t\t\tcase config.Hide:\n\t\t\t\t// make sure to fill if needed\n\t\t\t\tif padText, OK := e.shouldFill(block.Filler, space+length-e.currentLineLength); OK {\n\t\t\t\t\te.write(padText)\n\t\t\t\t}\n\n\t\t\t\te.currentLineLength = 0\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\tdefer func() {\n\t\t\te.currentLineLength = 0\n\t\t\te.Overflow = \"\"\n\t\t}()\n\n\t\t// validate if we have a filler and fill if needed\n\t\tif padText, OK := e.shouldFill(block.Filler, space); OK {\n\t\t\te.write(padText)\n\t\t\te.write(blockText)\n\t\t\treturn true\n\t\t}\n\n\t\tif space > 0 {\n\t\t\te.write(strings.Repeat(\" \", space))\n\t\t}\n\n\t\te.write(blockText)\n\tcase config.RPrompt:\n\t\te.rprompt = blockText\n\t\te.rpromptLength = length\n\t}\n\n\treturn true\n}\n\n// renderBlockFromCache re-renders a block using existing segment data without re-execution\nfunc (e *Engine) renderBlockFromCache(block *config.Block, cancelNewline bool) bool {\n\t// Re-render all segments in the block\n\tfor segmentIndex, segment := range block.Segments {\n\t\t// Allow pending segments to render (they show \"...\" text)\n\t\tif !segment.Pending && !segment.Enabled && segment.ResolveStyle() != config.Accordion {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Render segment text (will use pending state if still pending)\n\t\tif !segment.Render(segmentIndex, e.forceRender) {\n\t\t\tcontinue\n\t\t}\n\n\t\tif colors, newCycle := cycle.Loop(); colors != nil {\n\t\t\tcycle = &newCycle\n\t\t\tsegment.Foreground = colors.Foreground\n\t\t\tsegment.Background = colors.Background\n\t\t}\n\n\t\tif terminal.Len() == 0 && len(block.LeadingDiamond) > 0 {\n\t\t\tsegment.LeadingDiamond = block.LeadingDiamond\n\t\t}\n\n\t\te.setActiveSegment(segment)\n\t\te.renderActiveSegment()\n\t}\n\n\tif e.activeSegment != nil && len(block.TrailingDiamond) > 0 {\n\t\te.activeSegment.TrailingDiamond = block.TrailingDiamond\n\t}\n\n\te.writeSeparator(true)\n\te.activeSegment = nil\n\te.previousActiveSegment = nil\n\n\tblockText, length := terminal.String()\n\n\t// do not print anything when we don't have any text unless forced\n\tif !block.Force && length == 0 {\n\t\treturn false\n\t}\n\n\treturn e.writeBlock(block, blockText, length, cancelNewline)\n}\n\nfunc (e *Engine) applyPowerShellBleedPatch() {\n\t// when in PowerShell, we need to clear the line after the prompt\n\t// to avoid the background being printed on the next line\n\t// when at the end of the buffer.\n\t// See https://github.com/JanDeDobbeleer/oh-my-posh/issues/65\n\tif e.Env.Shell() != shell.PWSH {\n\t\treturn\n\t}\n\n\t// only do this when enabled\n\tif !e.Config.PatchPwshBleed {\n\t\treturn\n\t}\n\n\te.write(terminal.ClearAfter())\n}\n\nfunc (e *Engine) setActiveSegment(segment *config.Segment) {\n\te.activeSegment = segment\n\tterminal.Interactive = segment.Interactive\n\tterminal.SetColors(segment.ResolveBackground(), segment.ResolveForeground())\n}\n\nfunc (e *Engine) renderActiveSegment() {\n\te.writeSeparator(false)\n\n\tswitch e.activeSegment.ResolveStyle() {\n\tcase config.Plain, config.Powerline:\n\t\tterminal.Write(color.Background, color.Foreground, e.activeSegment.Text())\n\tcase config.Diamond:\n\t\tbackground := color.Transparent\n\n\t\tif e.previousActiveSegment != nil && e.previousActiveSegment.HasEmptyDiamondAtEnd() {\n\t\t\tbackground = e.previousActiveSegment.ResolveBackground()\n\t\t}\n\n\t\tterminal.Write(background, color.Background, e.activeSegment.LeadingDiamond)\n\t\tterminal.Write(color.Background, color.Foreground, e.activeSegment.Text())\n\tcase config.Accordion:\n\t\t// Render accordion segments if enabled OR pending (pending shows \"...\" text)\n\t\tif e.activeSegment.Enabled || e.activeSegment.Pending {\n\t\t\tterminal.Write(color.Background, color.Foreground, e.activeSegment.Text())\n\t\t}\n\t}\n\n\te.previousActiveSegment = e.activeSegment\n\n\tterminal.SetParentColors(e.previousActiveSegment.ResolveBackground(), e.previousActiveSegment.ResolveForeground())\n}\n\nfunc (e *Engine) writeSeparator(final bool) {\n\tif e.activeSegment == nil {\n\t\treturn\n\t}\n\n\tisCurrentDiamond := e.activeSegment.ResolveStyle() == config.Diamond\n\tif final && isCurrentDiamond {\n\t\tterminal.Write(color.Transparent, color.Background, e.activeSegment.TrailingDiamond)\n\t\treturn\n\t}\n\n\tisPreviousDiamond := e.previousActiveSegment != nil && e.previousActiveSegment.ResolveStyle() == config.Diamond\n\tif isPreviousDiamond {\n\t\te.adjustTrailingDiamondColorOverrides()\n\t}\n\n\tif isPreviousDiamond && isCurrentDiamond && e.activeSegment.LeadingDiamond == \"\" {\n\t\tterminal.Write(color.Background, color.ParentBackground, e.previousActiveSegment.TrailingDiamond)\n\t\treturn\n\t}\n\n\tif isPreviousDiamond && len(e.previousActiveSegment.TrailingDiamond) > 0 {\n\t\tterminal.Write(color.Transparent, color.ParentBackground, e.previousActiveSegment.TrailingDiamond)\n\t}\n\n\tisPowerline := e.activeSegment.IsPowerline()\n\n\tshouldOverridePowerlineLeadingSymbol := func() bool {\n\t\tif !isPowerline {\n\t\t\treturn false\n\t\t}\n\n\t\tif isPowerline && e.activeSegment.LeadingPowerlineSymbol == \"\" {\n\t\t\treturn false\n\t\t}\n\n\t\tif e.previousActiveSegment != nil && e.previousActiveSegment.IsPowerline() {\n\t\t\treturn false\n\t\t}\n\n\t\treturn true\n\t}\n\n\tif shouldOverridePowerlineLeadingSymbol() {\n\t\tterminal.Write(color.Transparent, color.Background, e.activeSegment.LeadingPowerlineSymbol)\n\t\treturn\n\t}\n\n\tresolvePowerlineSymbol := func() string {\n\t\tif isPowerline {\n\t\t\treturn e.activeSegment.PowerlineSymbol\n\t\t}\n\n\t\tif e.previousActiveSegment != nil && e.previousActiveSegment.IsPowerline() {\n\t\t\treturn e.previousActiveSegment.PowerlineSymbol\n\t\t}\n\n\t\treturn \"\"\n\t}\n\n\tsymbol := resolvePowerlineSymbol()\n\tif symbol == \"\" {\n\t\treturn\n\t}\n\n\tbgColor := color.Background\n\tif final || !isPowerline {\n\t\tbgColor = color.Transparent\n\t}\n\n\tif e.activeSegment.ResolveStyle() == config.Diamond && e.activeSegment.LeadingDiamond == \"\" {\n\t\tbgColor = color.Background\n\t}\n\n\tif e.activeSegment.InvertPowerline || (e.previousActiveSegment != nil && e.previousActiveSegment.InvertPowerline) {\n\t\tterminal.Write(e.getPowerlineColor(), bgColor, symbol)\n\t\treturn\n\t}\n\n\tterminal.Write(bgColor, e.getPowerlineColor(), symbol)\n}\n\nfunc (e *Engine) getPowerlineColor() color.Ansi {\n\tif e.previousActiveSegment == nil {\n\t\treturn color.Transparent\n\t}\n\n\tif e.previousActiveSegment.ResolveStyle() == config.Diamond && e.previousActiveSegment.TrailingDiamond == \"\" {\n\t\treturn e.previousActiveSegment.ResolveBackground()\n\t}\n\n\tif e.activeSegment.ResolveStyle() == config.Diamond && e.activeSegment.LeadingDiamond == \"\" {\n\t\treturn e.previousActiveSegment.ResolveBackground()\n\t}\n\n\tif !e.previousActiveSegment.IsPowerline() {\n\t\treturn color.Transparent\n\t}\n\n\treturn e.previousActiveSegment.ResolveBackground()\n}\n\nfunc (e *Engine) adjustTrailingDiamondColorOverrides() {\n\t// as we now already adjusted the activeSegment, we need to change the value\n\t// of background and foreground to parentBackground and parentForeground\n\t// this will still break when using parentBackground and parentForeground as keywords\n\t// in a trailing diamond, but let's fix that when it happens as it requires either a rewrite\n\t// of the logic for diamonds or storing grandparents as well like one happy family.\n\tif e.previousActiveSegment == nil || e.previousActiveSegment.TrailingDiamond == \"\" {\n\t\treturn\n\t}\n\n\ttrailingDiamond := e.previousActiveSegment.TrailingDiamond\n\t// Optimize: check both conditions in a single pass\n\thasBg := strings.Contains(trailingDiamond, string(color.Background))\n\thasFg := strings.Contains(trailingDiamond, string(color.Foreground))\n\n\tif !hasBg && !hasFg {\n\t\treturn\n\t}\n\n\tmatch := regex.FindNamedRegexMatch(terminal.AnchorRegex, trailingDiamond)\n\tif len(match) == 0 {\n\t\treturn\n\t}\n\n\tadjustOverride := func(anchor string, override color.Ansi) {\n\t\tnewOverride := override\n\t\tswitch override { //nolint:exhaustive\n\t\tcase color.Foreground:\n\t\t\tnewOverride = color.ParentForeground\n\t\tcase color.Background:\n\t\t\tnewOverride = color.ParentBackground\n\t\t}\n\n\t\tif override == newOverride {\n\t\t\treturn\n\t\t}\n\n\t\tnewAnchor := strings.Replace(match[terminal.ANCHOR], string(override), string(newOverride), 1)\n\t\te.previousActiveSegment.TrailingDiamond = strings.Replace(e.previousActiveSegment.TrailingDiamond, anchor, newAnchor, 1)\n\t}\n\n\tif len(match[terminal.BG]) > 0 {\n\t\tadjustOverride(match[terminal.ANCHOR], color.Ansi(match[terminal.BG]))\n\t}\n\n\tif len(match[terminal.FG]) > 0 {\n\t\tadjustOverride(match[terminal.ANCHOR], color.Ansi(match[terminal.FG]))\n\t}\n}\n\nfunc (e *Engine) rectifyTerminalWidth(diff int) {\n\t// Since the terminal width may not be given by the CLI flag, we should always call this here.\n\t_, err := e.Env.TerminalWidth()\n\tif err != nil {\n\t\t// Skip when we're unable to determine the terminal width.\n\t\treturn\n\t}\n\n\te.Env.Flags().TerminalWidth += diff\n}\n\n// New returns a prompt engine initialized with the\n// given configuration options, and is ready to print any\n// of the prompt components.\nfunc New(flags *runtime.Flags) *Engine {\n\tenv := &runtime.Terminal{}\n\tenv.Init(flags)\n\n\treload, _ := cache.Get[bool](cache.Device, config.RELOAD)\n\tcfg := config.Get(flags.ConfigPath, reload)\n\n\ttemplate.Init(env, cfg.Var, cfg.Maps)\n\n\tflags.HasExtra = cfg.DebugPrompt != nil ||\n\t\tcfg.SecondaryPrompt != nil ||\n\t\tcfg.TransientPrompt != nil ||\n\t\tcfg.ValidLine != nil ||\n\t\tcfg.ErrorLine != nil\n\n\t// when we print using https://github.com/akinomyoga/ble.sh, this needs to be unescaped for certain prompts\n\tsh := env.Shell()\n\tif sh == shell.BASH && !flags.Escape {\n\t\tsh = shell.GENERIC\n\t}\n\n\tterminal.Init(sh)\n\tterminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()\n\tterminal.Colors = cfg.MakeColors(env)\n\tterminal.Plain = flags.Plain\n\n\teng := &Engine{\n\t\tConfig:      cfg,\n\t\tEnv:         env,\n\t\tPlain:       flags.Plain,\n\t\tforceRender: flags.Force || len(env.Getenv(\"POSH_FORCE_RENDER\")) > 0,\n\t\tprompt:      strings.Builder{},\n\t}\n\n\t// Pre-allocate prompt builder capacity to reduce allocations during rendering\n\teng.prompt.Grow(512) // Start with 512 bytes capacity, will grow as needed\n\n\tswitch env.Shell() {\n\tcase shell.XONSH:\n\t\t// In Xonsh, the behavior of wrapping at the end of a prompt line is inconsistent across different operating systems.\n\t\t// On Windows, it wraps before the last cell on the terminal screen, that is, the last cell is never available for a prompt line.\n\t\tif env.GOOS() == runtime.WINDOWS {\n\t\t\teng.rectifyTerminalWidth(-1)\n\t\t}\n\tcase shell.ELVISH:\n\t\t// In Elvish, the case is similar to that in Xonsh.\n\t\t// However, on Windows, we have to reduce the terminal width by 1 again to ensure that newlines are displayed correctly.\n\t\tdiff := -1\n\t\tif env.GOOS() == runtime.WINDOWS {\n\t\t\tdiff = -2\n\t\t}\n\t\teng.rectifyTerminalWidth(diff)\n\tcase shell.PWSH:\n\t\t// when in PowerShell, and force patching the bleed bug\n\t\t// we need to reduce the terminal width by 1 so the last\n\t\t// character isn't cut off by the ANSI escape sequences\n\t\t// See https://github.com/JanDeDobbeleer/oh-my-posh/issues/65\n\t\tif cfg.PatchPwshBleed {\n\t\t\teng.rectifyTerminalWidth(-1)\n\t\t}\n\t}\n\n\treturn eng\n}\n"
  },
  {
    "path": "src/prompt/engine_test.go",
    "content": "package prompt\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCanWriteRPrompt(t *testing.T) {\n\tcases := []struct {\n\t\tTerminalWidthError error\n\t\tCase               string\n\t\tTerminalWidth      int\n\t\tPromptLength       int\n\t\tRPromptLength      int\n\t\tExpected           bool\n\t}{\n\t\t{Case: \"Width Error\", Expected: false, TerminalWidthError: errors.New(\"burp\")},\n\t\t{Case: \"Terminal > Prompt enabled\", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 10},\n\t\t{Case: \"Terminal > Prompt enabled edge\", Expected: true, TerminalWidth: 200, PromptLength: 100, RPromptLength: 70},\n\t\t{Case: \"Prompt > Terminal enabled\", Expected: true, TerminalWidth: 200, PromptLength: 300, RPromptLength: 70},\n\t\t{Case: \"Terminal > Prompt disabled no breathing\", Expected: false, TerminalWidth: 200, PromptLength: 100, RPromptLength: 71},\n\t\t{Case: \"Prompt > Terminal disabled no breathing\", Expected: false, TerminalWidth: 200, PromptLength: 300, RPromptLength: 80},\n\t\t{Case: \"Prompt > Terminal disabled no room\", Expected: true, TerminalWidth: 200, PromptLength: 400, RPromptLength: 80},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"TerminalWidth\").Return(tc.TerminalWidth, tc.TerminalWidthError)\n\t\tengine := &Engine{\n\t\t\tEnv:               env,\n\t\t\trpromptLength:     tc.RPromptLength,\n\t\t\tcurrentLineLength: tc.PromptLength,\n\t\t\trprompt:           \"hello\",\n\t\t}\n\n\t\t_, got := engine.canWriteRightBlock(tc.RPromptLength, true)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestPrintPWD(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tConfig   string\n\t\tPwd      string\n\t\tShell    string\n\t\tCygwin   bool\n\t}{\n\t\t{Case: \"Empty PWD\"},\n\t\t{Case: \"OSC99\", Config: terminal.OSC99, Expected: \"\\x1b]9;9;pwd\\x1b\\\\\"},\n\t\t{Case: \"OSC99 - Elvish\", Config: terminal.OSC99, Shell: shell.ELVISH},\n\t\t{Case: \"OSC7\", Config: terminal.OSC7, Expected: \"\\x1b]7;file://host/pwd\\x1b\\\\\"},\n\t\t{Case: \"OSC51\", Config: terminal.OSC51, Expected: \"\\x1b]51;Auser@host:pwd\\x1b\\\\\"},\n\t\t{Case: \"Template (empty)\", Config: \"{{ if eq .Shell \\\"pwsh\\\" }}osc7{{ end }}\"},\n\t\t{Case: \"Template (non empty)\", Shell: shell.GENERIC, Config: \"{{ if eq .Shell \\\"shell\\\" }}osc7{{ end }}\", Expected: \"\\x1b]7;file://host/pwd\\x1b\\\\\"},\n\t\t{\n\t\t\tCase:     \"OSC99 Cygwin\",\n\t\t\tPwd:      `C:\\Users\\user\\Documents\\GitHub\\oh-my-posh`,\n\t\t\tConfig:   terminal.OSC99,\n\t\t\tCygwin:   true,\n\t\t\tExpected: \"\\x1b]9;9;C:/Users/user/Documents/GitHub/oh-my-posh\\x1b\\\\\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"OSC99 Windows\",\n\t\t\tPwd:      `C:\\Users\\user\\Documents\\GitHub\\oh-my-posh`,\n\t\t\tConfig:   terminal.OSC99,\n\t\t\tExpected: \"\\x1b]9;9;C:\\\\Users\\\\user\\\\Documents\\\\GitHub\\\\oh-my-posh\\x1b\\\\\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tif tc.Pwd == \"\" {\n\t\t\ttc.Pwd = \"pwd\"\n\t\t}\n\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"User\").Return(\"user\")\n\t\tenv.On(\"Shell\").Return(tc.Shell)\n\t\tenv.On(\"IsCygwin\").Return(tc.Cygwin)\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"Host\").Return(\"host\", nil)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell: tc.Shell,\n\t\t\t},\n\t\t\tSegments: maps.NewConcurrent[any](),\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tterminal.Init(shell.GENERIC)\n\n\t\tengine := &Engine{\n\t\t\tEnv: env,\n\t\t\tConfig: &config.Config{\n\t\t\t\tPWD: tc.Config,\n\t\t\t},\n\t\t}\n\n\t\tengine.pwd()\n\t\tgot := engine.string()\n\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestPrintPWDWSL(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tConfig   string\n\t\tPwd      string\n\t\tShell    string\n\t\tWinPath  string\n\t\tIsWsl    bool\n\t}{\n\t\t{\n\t\t\tCase:     \"OSC99 WSL\",\n\t\t\tPwd:      \"/home/user/projects\",\n\t\t\tConfig:   terminal.OSC99,\n\t\t\tIsWsl:    true,\n\t\t\tWinPath:  \"//wsl.localhost/Ubuntu/home/user/projects\",\n\t\t\tExpected: \"\\x1b]9;9;//wsl.localhost/Ubuntu/home/user/projects\\x1b\\\\\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"OSC99 Not WSL\",\n\t\t\tPwd:      \"/home/user/projects\",\n\t\t\tConfig:   terminal.OSC99,\n\t\t\tIsWsl:    false,\n\t\t\tExpected: \"\\x1b]9;9;/home/user/projects\\x1b\\\\\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"OSC7 WSL (with conversion)\",\n\t\t\tPwd:      \"/home/user/projects\",\n\t\t\tConfig:   terminal.OSC7,\n\t\t\tIsWsl:    true,\n\t\t\tWinPath:  \"//wsl.localhost/Ubuntu/home/user/projects\",\n\t\t\tExpected: \"\\x1b]7;file://host///wsl.localhost/Ubuntu/home/user/projects\\x1b\\\\\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"OSC51 WSL (with conversion)\",\n\t\t\tPwd:      \"/home/user/projects\",\n\t\t\tConfig:   terminal.OSC51,\n\t\t\tIsWsl:    true,\n\t\t\tWinPath:  \"//wsl.localhost/Ubuntu/home/user/projects\",\n\t\t\tExpected: \"\\x1b]51;Auser@host://wsl.localhost/Ubuntu/home/user/projects\\x1b\\\\\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"User\").Return(\"user\")\n\t\tenv.On(\"Shell\").Return(tc.Shell)\n\t\tenv.On(\"IsCygwin\").Return(false)\n\t\tenv.On(\"IsWsl\").Return(tc.IsWsl)\n\t\tenv.On(\"Host\").Return(\"host\", nil)\n\n\t\tif tc.IsWsl {\n\t\t\tif tc.WinPath == \"\" {\n\t\t\t\ttc.WinPath = tc.Pwd\n\t\t\t}\n\t\t\tenv.On(\"ConvertToWindowsPath\", tc.Pwd).Return(tc.WinPath)\n\t\t}\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell: tc.Shell,\n\t\t\t},\n\t\t\tSegments: maps.NewConcurrent[any](),\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tterminal.Init(shell.GENERIC)\n\n\t\tengine := &Engine{\n\t\t\tEnv: env,\n\t\t\tConfig: &config.Config{\n\t\t\t\tPWD: tc.Config,\n\t\t\t},\n\t\t}\n\n\t\tengine.pwd()\n\t\tgot := engine.string()\n\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc BenchmarkEngineRender(b *testing.B) {\n\tfor b.Loop() {\n\t\tengineRender()\n\t}\n}\n\nfunc engineRender() {\n\tcfg := config.Load(\"\")\n\n\tenv := &runtime.Terminal{}\n\tenv.Init(nil)\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\n\tterminal.Init(shell.GENERIC)\n\tterminal.BackgroundColor = cfg.TerminalBackground.ResolveTemplate()\n\tterminal.Colors = cfg.MakeColors(env)\n\n\tengine := &Engine{\n\t\tConfig: cfg,\n\t\tEnv:    env,\n\t}\n\n\tengine.Primary()\n}\n\nfunc TestGetTitle(t *testing.T) {\n\tcases := []struct {\n\t\tTemplate      string\n\t\tUser          string\n\t\tCwd           string\n\t\tPathSeparator string\n\t\tShellName     string\n\t\tExpected      string\n\t\tRoot          bool\n\t}{\n\t\t{\n\t\t\tTemplate:      \"{{.Env.USERDOMAIN}} :: {{.PWD}}{{if .Root}} :: Admin{{end}} :: {{.Shell}}\",\n\t\t\tCwd:           \"C:\\\\vagrant\",\n\t\t\tPathSeparator: \"\\\\\",\n\t\t\tShellName:     \"PowerShell\",\n\t\t\tRoot:          true,\n\t\t\tExpected:      \"\\x1b]0;MyCompany :: C:\\\\vagrant :: Admin :: PowerShell\\a\",\n\t\t},\n\t\t{\n\t\t\tTemplate:      \"{{.Folder}}{{if .Root}} :: Admin{{end}} :: {{.Shell}}\",\n\t\t\tCwd:           \"C:\\\\vagrant\",\n\t\t\tPathSeparator: \"\\\\\",\n\t\t\tShellName:     \"PowerShell\",\n\t\t\tExpected:      \"\\x1b]0;vagrant :: PowerShell\\a\",\n\t\t},\n\t\t{\n\t\t\tTemplate:      \"{{.UserName}}@{{.HostName}}{{if .Root}} :: Admin{{end}} :: {{.Shell}}\",\n\t\t\tRoot:          true,\n\t\t\tUser:          \"MyUser\",\n\t\t\tPathSeparator: \"\\\\\",\n\t\t\tShellName:     \"PowerShell\",\n\t\t\tExpected:      \"\\x1b]0;MyUser@MyHost :: Admin :: PowerShell\\a\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Pwd\").Return(tc.Cwd)\n\t\tenv.On(\"Home\").Return(\"/usr/home\")\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tenv.On(\"Getenv\", \"USERDOMAIN\").Return(\"MyCompany\")\n\t\tenv.On(\"Shell\").Return(tc.ShellName)\n\n\t\tterminal.Init(shell.GENERIC)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell:    tc.ShellName,\n\t\t\t\tUserName: \"MyUser\",\n\t\t\t\tRoot:     tc.Root,\n\t\t\t\tHostName: \"MyHost\",\n\t\t\t\tPWD:      tc.Cwd,\n\t\t\t\tFolder:   \"vagrant\",\n\t\t\t},\n\t\t\tSegments: maps.NewConcurrent[any](),\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tengine := &Engine{\n\t\t\tConfig: &config.Config{\n\t\t\t\tConsoleTitleTemplate: tc.Template,\n\t\t\t},\n\t\t\tEnv: env,\n\t\t}\n\n\t\ttitle := engine.getTitleTemplateText()\n\t\tgot := terminal.FormatTitle(title)\n\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {\n\tcases := []struct {\n\t\tTemplate      string\n\t\tUser          string\n\t\tCwd           string\n\t\tPathSeparator string\n\t\tShellName     string\n\t\tExpected      string\n\t\tRoot          bool\n\t}{\n\t\t{\n\t\t\tTemplate:      \"Not using Host only {{.UserName}} and {{.Shell}}\",\n\t\t\tUser:          \"MyUser\",\n\t\t\tPathSeparator: \"\\\\\",\n\t\t\tShellName:     \"PowerShell\",\n\t\t\tExpected:      \"\\x1b]0;Not using Host only MyUser and PowerShell\\a\",\n\t\t},\n\t\t{\n\t\t\tTemplate:      \"{{.UserName}}@{{.HostName}} :: {{.Shell}}\",\n\t\t\tUser:          \"MyUser\",\n\t\t\tPathSeparator: \"\\\\\",\n\t\t\tShellName:     \"PowerShell\",\n\t\t\tExpected:      \"\\x1b]0;MyUser@ :: PowerShell\\a\",\n\t\t},\n\t\t{\n\t\t\tTemplate: \"\\x1b[93m[\\x1b[39m\\x1b[96mconsole-title\\x1b[39m\\x1b[96m ≡\\x1b[39m\\x1b[31m +0\\x1b[39m\\x1b[31m ~1\\x1b[39m\\x1b[31m -0\\x1b[39m\\x1b[31m !\\x1b[39m\\x1b[93m]\\x1b[39m\",\n\t\t\tExpected: \"\\x1b]0;[console-title ≡ +0 ~1 -0 !]\\a\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Pwd\").Return(tc.Cwd)\n\t\tenv.On(\"Home\").Return(\"/usr/home\")\n\t\tenv.On(\"Getenv\", \"USERDOMAIN\").Return(\"MyCompany\")\n\t\tenv.On(\"Shell\").Return(tc.ShellName)\n\n\t\tterminal.Init(shell.GENERIC)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell:    tc.ShellName,\n\t\t\t\tUserName: \"MyUser\",\n\t\t\t\tRoot:     tc.Root,\n\t\t\t\tHostName: \"\",\n\t\t\t},\n\t\t\tSegments: maps.NewConcurrent[any](),\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tengine := &Engine{\n\t\t\tConfig: &config.Config{\n\t\t\t\tConsoleTitleTemplate: tc.Template,\n\t\t\t},\n\t\t\tEnv: env,\n\t\t}\n\n\t\ttitle := engine.getTitleTemplateText()\n\t\tgot := terminal.FormatTitle(title)\n\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestShouldFill(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tOverflow       config.Overflow\n\t\tExpectedFiller string\n\t\tBlock          config.Block\n\t\tPadding        int\n\t\tExpectedBool   bool\n\t}{\n\t\t{\n\t\t\tCase:           \"Plain single character with no padding\",\n\t\t\tPadding:        0,\n\t\t\tExpectedFiller: \"\",\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Plain single character with 1 padding\",\n\t\t\tPadding:        1,\n\t\t\tExpectedFiller: \"-\",\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Plain single character with lots of padding\",\n\t\t\tPadding:        200,\n\t\t\tExpectedFiller: strings.Repeat(\"-\", 200),\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Plain multi-character with some padding\",\n\t\t\tPadding:        20,\n\t\t\tExpectedFiller: strings.Repeat(\"-^-\", 6) + \"  \",\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"-^-\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Template conditional on overflow with no overflow\",\n\t\t\tPadding:        3,\n\t\t\tExpectedFiller: strings.Repeat(\"X\", 3),\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"{{ if .Overflow -}} O {{- else -}} X {{- end }}\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Template conditional on overflow with an overflow\",\n\t\t\tOverflow:       config.Break,\n\t\t\tPadding:        3,\n\t\t\tExpectedFiller: strings.Repeat(\"O\", 3),\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Hide,\n\t\t\t\tFiller:   \"{{ if .Overflow -}} O {{- else -}} X {{- end }}\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Template conditional on overflow break\",\n\t\t\tOverflow:       config.Break,\n\t\t\tPadding:        3,\n\t\t\tExpectedFiller: strings.Repeat(\"O\", 3),\n\t\t\tExpectedBool:   true,\n\t\t\tBlock: config.Block{\n\t\t\t\tOverflow: config.Break,\n\t\t\t\tFiller:   `{{ if eq .Overflow \"break\" -}} O {{- else -}} X {{- end }}`,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\n\t\tengine := &Engine{\n\t\t\tEnv:      env,\n\t\t\tOverflow: tc.Overflow,\n\t\t}\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell: shell.GENERIC,\n\t\t\t},\n\t\t\tSegments: maps.NewConcurrent[any](),\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tterminal.Init(shell.GENERIC)\n\t\tterminal.Plain = true\n\t\tterminal.Colors = &color.Defaults{}\n\n\t\tgotFiller, gotBool := engine.shouldFill(tc.Block.Filler, tc.Padding)\n\n\t\tassert.Equal(t, tc.ExpectedFiller, gotFiller, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBool, gotBool, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/prompt/extra.go",
    "content": "package prompt\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\ntype ExtraPromptType int\n\nconst (\n\tTransient ExtraPromptType = iota\n\tValid\n\tError\n\tSecondary\n\tDebug\n)\n\nfunc (e *Engine) ExtraPrompt(promptType ExtraPromptType) string {\n\tvar prompt *config.Segment\n\n\tswitch promptType {\n\tcase Debug:\n\t\tprompt = e.Config.DebugPrompt\n\tcase Transient:\n\t\tprompt = e.Config.TransientPrompt\n\tcase Valid:\n\t\tprompt = e.Config.ValidLine\n\tcase Error:\n\t\tprompt = e.Config.ErrorLine\n\tcase Secondary:\n\t\tprompt = e.Config.SecondaryPrompt\n\t}\n\n\tif prompt == nil {\n\t\tprompt = &config.Segment{}\n\t}\n\n\tgetTemplate := func(template string) string {\n\t\tif len(template) != 0 {\n\t\t\treturn template\n\t\t}\n\t\tswitch promptType { //nolint: exhaustive\n\t\tcase Debug:\n\t\t\treturn \"[DBG]: \"\n\t\tcase Transient:\n\t\t\treturn \"{{ .Shell }}> \"\n\t\tcase Secondary:\n\t\t\treturn \"> \"\n\t\tdefault:\n\t\t\treturn \"\"\n\t\t}\n\t}\n\n\tpromptText, err := template.Render(getTemplate(prompt.Template), nil)\n\tif err != nil {\n\t\tpromptText = err.Error()\n\t}\n\n\tif promptType == Transient && prompt.Newline {\n\t\tpromptText = fmt.Sprintf(\"%s%s\", e.getNewline(), promptText)\n\t}\n\n\tif promptType == Transient && e.Config.ShellIntegration {\n\t\texitCode, _ := e.Env.StatusCodes()\n\t\te.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))\n\t\te.write(terminal.PromptStart())\n\t}\n\n\tforeground := color.Ansi(prompt.ForegroundTemplates.FirstMatch(nil, string(prompt.Foreground)))\n\tbackground := color.Ansi(prompt.BackgroundTemplates.FirstMatch(nil, string(prompt.Background)))\n\tterminal.SetColors(background, foreground)\n\tterminal.Write(background, foreground, promptText)\n\n\tstr, length := terminal.String()\n\n\tif promptType == Transient && len(prompt.Filler) != 0 {\n\t\tconsoleWidth, err := e.Env.TerminalWidth()\n\t\tif err == nil || consoleWidth != 0 {\n\t\t\tif padText, OK := e.shouldFill(prompt.Filler, consoleWidth-length); OK {\n\t\t\t\tstr += padText\n\t\t\t}\n\t\t}\n\t}\n\n\tswitch e.Env.Shell() {\n\tcase shell.ZSH:\n\t\tif promptType == Transient {\n\t\t\tif !e.Env.Flags().Eval {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tprompt := fmt.Sprintf(\"PS1=%s\", shell.QuotePosixStr(str))\n\t\t\t// empty RPROMPT\n\t\t\tprompt += \"\\nRPROMPT=''\"\n\t\t\treturn prompt\n\t\t}\n\tcase shell.PWSH:\n\t\tif promptType == Transient {\n\t\t\t// clear the line afterwards to prevent text from being written on the same line\n\t\t\t// see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3628\n\t\t\treturn str + terminal.ClearAfter()\n\t\t}\n\t}\n\n\treturn str\n}\n"
  },
  {
    "path": "src/prompt/preview.go",
    "content": "package prompt\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nfunc (e *Engine) Preview() string {\n\tbuilder := text.NewBuilder()\n\n\tprintPrompt := func(title, prompt string) {\n\t\tbuilder.WriteString(log.Text(fmt.Sprintf(\"\\n%s:\\n\\n\", title)).Bold().Plain().String())\n\t\tbuilder.WriteString(prompt)\n\t\tbuilder.WriteString(\"\\n\")\n\t}\n\n\tprintPrompt(\"Primary\", e.Primary())\n\n\tright := e.RPrompt()\n\tif len(right) > 0 {\n\t\tprintPrompt(\"Right\", right)\n\t}\n\n\tif e.Config.SecondaryPrompt != nil {\n\t\tprintPrompt(\"Secondary\", e.ExtraPrompt(Secondary))\n\t}\n\n\tif e.Config.TransientPrompt != nil {\n\t\tprintPrompt(\"Transient\", e.ExtraPrompt(Transient))\n\t}\n\n\tif e.Config.DebugPrompt != nil {\n\t\tprintPrompt(\"Debug\", e.ExtraPrompt(Debug))\n\t}\n\n\tif e.Config.ValidLine != nil {\n\t\tprintPrompt(\"Valid\", e.ExtraPrompt(Valid))\n\t}\n\n\tif e.Config.ErrorLine != nil {\n\t\tprintPrompt(\"Error\", e.ExtraPrompt(Error))\n\t}\n\n\tbuilder.WriteString(\"\\n\")\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "src/prompt/primary.go",
    "content": "package prompt\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\nfunc (e *Engine) Primary() string {\n\treturn e.primaryInternal(false)\n}\n\n// primaryInternal handles both regular and streaming prompt rendering\nfunc (e *Engine) primaryInternal(fromCache bool) string {\n\tneedsPrimaryRightPrompt := e.needsPrimaryRightPrompt()\n\n\te.writePrimaryPromptInternal(needsPrimaryRightPrompt, fromCache)\n\n\tswitch e.Env.Shell() {\n\tcase shell.ZSH:\n\t\tif !e.Env.Flags().Eval {\n\t\t\tbreak\n\t\t}\n\n\t\t// Warp doesn't support RPROMPT so we need to write it manually\n\t\tif e.isWarp() {\n\t\t\te.writePrimaryRightPrompt()\n\t\t\tprompt := fmt.Sprintf(\"PS1=%s\", shell.QuotePosixStr(e.string()))\n\t\t\treturn prompt\n\t\t}\n\n\t\tprompt := fmt.Sprintf(\"PS1=%s\", shell.QuotePosixStr(e.string()))\n\t\tprompt += fmt.Sprintf(\"\\nRPROMPT=%s\", shell.QuotePosixStr(e.rprompt))\n\n\t\treturn prompt\n\tdefault:\n\t\tif !needsPrimaryRightPrompt {\n\t\t\tbreak\n\t\t}\n\n\t\te.writePrimaryRightPrompt()\n\t}\n\n\treturn e.string()\n}\n\nfunc (e *Engine) writePrimaryPrompt(needsPrimaryRPrompt bool) {\n\te.writePrimaryPromptInternal(needsPrimaryRPrompt, false)\n}\n\n// writePrimaryPromptInternal handles both regular and streaming prompt rendering\nfunc (e *Engine) writePrimaryPromptInternal(needsPrimaryRPrompt, fromCache bool) {\n\tif e.Config.ShellIntegration {\n\t\texitCode, _ := e.Env.StatusCodes()\n\t\te.write(terminal.CommandFinished(exitCode, e.Env.Flags().NoExitCode))\n\t\te.write(terminal.PromptStart())\n\t}\n\n\t// cache a pointer to the color cycle\n\tcycle = &e.Config.Cycle\n\tvar cancelNewline, didRender bool\n\n\t// Choose block source based on whether we're rendering from cache\n\tblocks := e.Config.Blocks\n\tif fromCache {\n\t\tblocks = e.allBlocks\n\t}\n\n\tfor i, block := range blocks {\n\t\t// do not print a leading newline when we're at the first row and the prompt is cleared\n\t\tif i == 0 {\n\t\t\trow, _ := e.Env.CursorPosition()\n\t\t\tcancelNewline = e.Env.Flags().Cleared || e.Env.Flags().PromptCount == 1 || row == 1\n\t\t}\n\n\t\t// skip setting a newline when we didn't print anything yet\n\t\tif i != 0 {\n\t\t\tcancelNewline = !didRender\n\t\t}\n\n\t\tif block.Type == config.RPrompt && !needsPrimaryRPrompt {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Choose render method based on whether we're rendering from cache\n\t\tvar rendered bool\n\t\tif fromCache {\n\t\t\trendered = e.renderBlockFromCache(block, cancelNewline)\n\t\t} else {\n\t\t\trendered = e.renderBlock(block, cancelNewline)\n\t\t}\n\n\t\tif rendered {\n\t\t\tdidRender = true\n\t\t}\n\n\t\t// Only handle tooltip caching in regular (non-cached) rendering\n\t\tif !fromCache && !e.Config.ToolTipsAction.IsDefault() {\n\t\t\tcache.Set(cache.Session, RPromptKey, e.rprompt, cache.INFINITE)\n\t\t\tcache.Set(cache.Session, RPromptLengthKey, e.rpromptLength, cache.INFINITE)\n\t\t}\n\t}\n\n\tif len(e.Config.ConsoleTitleTemplate) > 0 && !e.Env.Flags().Plain {\n\t\ttitle := e.getTitleTemplateText()\n\t\te.write(terminal.FormatTitle(title))\n\t}\n\n\tif e.Config.FinalSpace {\n\t\te.write(\" \")\n\t\te.currentLineLength++\n\t}\n\n\tif e.Config.ITermFeatures != nil && e.isIterm() {\n\t\thost, _ := e.Env.Host()\n\t\te.write(terminal.RenderItermFeatures(e.Config.ITermFeatures, e.Env.Shell(), e.Env.Pwd(), e.Env.User(), host))\n\t}\n\n\tif e.Config.ShellIntegration {\n\t\te.write(terminal.CommandStart())\n\t}\n\n\te.pwd()\n}\n\nfunc (e *Engine) needsPrimaryRightPrompt() bool {\n\tif e.Env.Flags().Debug {\n\t\treturn true\n\t}\n\n\tswitch e.Env.Shell() {\n\tcase shell.PWSH, shell.GENERIC, shell.ZSH:\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\nfunc (e *Engine) writePrimaryRightPrompt() {\n\tspace, OK := e.canWriteRightBlock(e.rpromptLength, true)\n\tif !OK {\n\t\treturn\n\t}\n\n\te.write(terminal.SaveCursorPosition())\n\te.write(strings.Repeat(\" \", space))\n\te.write(e.rprompt)\n\te.write(terminal.RestoreCursorPosition())\n}\n"
  },
  {
    "path": "src/prompt/rprompt.go",
    "content": "package prompt\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n)\n\nconst (\n\tRPromptKey       = \"rprompt\"\n\tRPromptLengthKey = \"rprompt_length\"\n)\n\nfunc (e *Engine) RPrompt() string {\n\tvar rprompt *config.Block\n\n\tfor _, block := range e.Config.Blocks {\n\t\tif block.Type != config.RPrompt {\n\t\t\tcontinue\n\t\t}\n\n\t\trprompt = block\n\t\tbreak\n\t}\n\n\tif rprompt == nil {\n\t\treturn \"\"\n\t}\n\n\ttext, length := e.writeBlockSegments(rprompt)\n\n\t// do not print anything when we don't have any text\n\tif length == 0 {\n\t\treturn \"\"\n\t}\n\n\te.rpromptLength = length\n\n\tif e.Env.Shell() == shell.ELVISH && e.Env.GOOS() != runtime.WINDOWS {\n\t\t// Workaround to align with a right-aligned block on non-Windows systems.\n\t\ttext += \" \"\n\t}\n\n\tif !e.Config.ToolTipsAction.IsDefault() {\n\t\tcache.Set(cache.Session, RPromptKey, text, cache.INFINITE)\n\t\tcache.Set(cache.Session, RPromptLengthKey, e.rpromptLength, cache.INFINITE)\n\t}\n\n\treturn text\n}\n"
  },
  {
    "path": "src/prompt/segments.go",
    "content": "package prompt\n\nimport (\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\trunjobs \"github.com/jandedobbeleer/oh-my-posh/src/runtime/jobs\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\ntype result struct {\n\tsegment *config.Segment\n\tindex   int\n}\n\nfunc (e *Engine) writeBlockSegments(block *config.Block) (string, int) {\n\tlength := len(block.Segments)\n\n\tif length == 0 {\n\t\treturn \"\", 0\n\t}\n\n\tout := make(chan result, length)\n\n\te.writeSegmentsConcurrently(block.Segments, out)\n\n\te.writeSegments(out, block)\n\n\tif e.activeSegment != nil && len(block.TrailingDiamond) > 0 {\n\t\te.activeSegment.TrailingDiamond = block.TrailingDiamond\n\t}\n\n\te.writeSeparator(true)\n\n\te.activeSegment = nil\n\te.previousActiveSegment = nil\n\n\treturn terminal.String()\n}\n\n// writeSegmentsConcurrently uses individual goroutines for each segment\nfunc (e *Engine) writeSegmentsConcurrently(segments []*config.Segment, out chan result) {\n\tfor i, segment := range segments {\n\t\t// In streaming mode, pre-register all segments as pending\n\t\t// This ensures countPendingSegments() sees them before timeout occurs\n\t\tif e.Env.Flags().Streaming {\n\t\t\tsegment.Timeout = e.Config.Streaming\n\t\t\te.pendingSegments.Store(segment.Name(), true)\n\t\t}\n\n\t\tgo func(segment *config.Segment, index int) {\n\t\t\tif segment.Timeout > 0 {\n\t\t\t\te.executeSegmentWithTimeout(segment)\n\t\t\t} else {\n\t\t\t\tsegment.Execute(e.Env)\n\t\t\t}\n\n\t\t\tout <- result{segment, index}\n\n\t\t\t// In streaming mode, clean up pre-registered segments that completed before timeout\n\t\t\tif e.Env.Flags().Streaming && segment.Timeout > 0 && !segment.Pending {\n\t\t\t\te.pendingSegments.Delete(segment.Name())\n\t\t\t}\n\t\t}(segment, i)\n\t}\n}\n\n// executeSegmentWithTimeout handles segment execution with timeout logic\nfunc (e *Engine) executeSegmentWithTimeout(segment *config.Segment) {\n\tdone := make(chan bool)\n\tgidChan := make(chan uint64, 1)\n\n\tgo func() {\n\t\tgidChan <- runjobs.CurrentGID()\n\t\tsegment.Execute(e.Env)\n\t\tclose(done)\n\t}()\n\n\tgid := <-gidChan\n\n\tselect {\n\tcase <-done:\n\t\t// Completed before timeout - nothing extra to do\n\tcase <-time.After(time.Duration(segment.Timeout) * time.Millisecond):\n\t\tlog.Errorf(\"timeout after %dms for segment: %s\", segment.Timeout, segment.Name())\n\n\t\t// When streaming is enabled, don't kill goroutines - let them continue executing\n\t\tif e.Env.Flags().Streaming {\n\t\t\tsegment.Pending = true\n\t\t\t// Note: Do NOT set segment.Enabled here - that would race with Execute()\n\t\t\t// Rendering logic handles Pending state to display \"...\" text\n\n\t\t\t// Track this segment as pending and continue execution in background\n\t\t\te.trackPendingSegment(segment, done)\n\t\t\treturn\n\t\t}\n\n\t\t// For non-streaming mode, kill the goroutine\n\t\tif err := runjobs.KillGoroutineChildren(gid); err != nil {\n\t\t\tlog.Errorf(\"failed to kill child processes for goroutine %d (segment: %s): %v\", gid, segment.Name(), err)\n\t\t}\n\t}\n}\n\nfunc (e *Engine) writeSegments(out chan result, block *config.Block) {\n\tcount := len(block.Segments)\n\tcurrent := 0\n\texecutedCount := 0\n\tresults := make([]*config.Segment, count)\n\t// Pre-allocate map with known capacity to reduce allocations\n\texecuted := make(map[string]bool, count)\n\tsegmentIndex := 0\n\n\t// Process results as they come in, eliminating busy waiting\n\tfor executedCount < count {\n\t\tres := <-out // Block until result is available\n\t\texecutedCount++\n\n\t\tresults[res.index] = res.segment\n\t\texecuted[res.segment.Name()] = true\n\n\t\t// Process segments that can now be rendered\n\t\tfor current < count && results[current] != nil {\n\t\t\tsegment := results[current]\n\t\t\tif !e.canRenderSegment(segment, executed) {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tif segment.Render(segmentIndex, e.forceRender) {\n\t\t\t\tsegmentIndex++\n\t\t\t}\n\n\t\t\te.writeSegment(block, segment)\n\t\t\tcurrent++\n\t\t}\n\t}\n\n\t// render all remaining segments where the needs can't be resolved\n\tfor current < executedCount {\n\t\tsegment := results[current]\n\t\tif segment.Render(segmentIndex, e.forceRender) {\n\t\t\tsegmentIndex++\n\t\t}\n\n\t\te.writeSegment(block, segment)\n\t\tcurrent++\n\t}\n}\n\nfunc (e *Engine) writeSegment(block *config.Block, segment *config.Segment) {\n\t// Allow pending segments to render (they show \"...\" text)\n\tif !segment.Pending && !segment.Enabled && segment.ResolveStyle() != config.Accordion {\n\t\treturn\n\t}\n\n\tif colors, newCycle := cycle.Loop(); colors != nil {\n\t\tcycle = &newCycle\n\t\tsegment.Foreground = colors.Foreground\n\t\tsegment.Background = colors.Background\n\t}\n\n\tif terminal.Len() == 0 && len(block.LeadingDiamond) > 0 {\n\t\tsegment.LeadingDiamond = block.LeadingDiamond\n\t}\n\n\te.setActiveSegment(segment)\n\te.renderActiveSegment()\n}\n\n// canRenderSegment now uses map for O(1) lookups instead of O(n) slice search\nfunc (e *Engine) canRenderSegment(segment *config.Segment, executed map[string]bool) bool {\n\tfor _, name := range segment.Needs {\n\t\tif !executed[name] {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "src/prompt/segments_test.go",
    "content": "package prompt\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRenderBlock(t *testing.T) {\n\tengine := New(&runtime.Flags{\n\t\tIsPrimary: true,\n\t})\n\tblock := &config.Block{\n\t\tSegments: []*config.Segment{\n\t\t\t{\n\t\t\t\tType:       \"text\",\n\t\t\t\tTemplate:   \"Hello\",\n\t\t\t\tForeground: \"red\",\n\t\t\t\tBackground: \"blue\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tType:       \"text\",\n\t\t\t\tTemplate:   \"World\",\n\t\t\t\tForeground: \"red\",\n\t\t\t\tBackground: \"blue\",\n\t\t\t},\n\t\t},\n\t}\n\n\tprompt, length := engine.writeBlockSegments(block)\n\tassert.Equal(t, \"\\x1b[44m\\x1b[31mHello\\x1b[0m\\x1b[44m\\x1b[31mWorld\\x1b[0m\", prompt)\n\tassert.Equal(t, 10, length)\n}\n\nfunc TestCanRenderSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExecuted map[string]bool\n\t\tNeeds    []string\n\t\tExpected bool\n\t}{\n\t\t{\n\t\t\tCase:     \"No cross segment dependencies\",\n\t\t\tExpected: true,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Cross segment dependencies, nothing executed\",\n\t\t\tExpected: false,\n\t\t\tNeeds:    []string{\"Foo\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Cross segment dependencies, available\",\n\t\t\tExpected: true,\n\t\t\tExecuted: map[string]bool{\n\t\t\t\t\"Foo\": true,\n\t\t\t},\n\t\t\tNeeds: []string{\"Foo\"},\n\t\t},\n\t}\n\tfor _, c := range cases {\n\t\tsegment := &config.Segment{\n\t\t\tType:  \"text\",\n\t\t\tNeeds: c.Needs,\n\t\t}\n\n\t\tengine := &Engine{}\n\t\tgot := engine.canRenderSegment(segment, c.Executed)\n\n\t\tassert.Equal(t, c.Expected, got, c.Case)\n\t}\n}\n\nfunc TestExecuteSegmentWithTimeout_Streaming(t *testing.T) {\n\t// This test verifies that when streaming is enabled and a timeout occurs,\n\t// the segment is marked as pending and tracked for later completion\n\tenv := new(mock.Environment)\n\tenv.On(\"Flags\").Return(&runtime.Flags{Streaming: true})\n\n\tsegment := &config.Segment{\n\t\tType:    \"text\",\n\t\tTimeout: 1, // Very short timeout to ensure it triggers\n\t}\n\n\tengine := &Engine{\n\t\tEnv:              env,\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\t// Create a mock segment that will definitely timeout\n\t// We'll use the actual timeout mechanism by making the execution slow\n\tdone := make(chan bool)\n\tgo func() {\n\t\ttime.Sleep(100 * time.Millisecond) // Longer than timeout\n\t\tclose(done)\n\t}()\n\n\t// Pre-register segment as pending (this happens in writeSegmentsConcurrently)\n\tengine.pendingSegments.Store(segment.Name(), true)\n\n\t// Mark as pending and track (simulating what executeSegmentWithTimeout does)\n\tsegment.Pending = true\n\tengine.trackPendingSegment(segment, done)\n\n\t// Verify it was tracked as pending\n\t_, exists := engine.pendingSegments.Load(segment.Name())\n\tassert.True(t, exists, \"Segment should be tracked as pending\")\n\n\t// Wait for completion notification\n\tselect {\n\tcase completed := <-engine.streamingResults:\n\t\tassert.Equal(t, segment, completed)\n\t\tassert.False(t, completed.Pending, \"Segment should no longer be pending after completion\")\n\tcase <-time.After(200 * time.Millisecond):\n\t\tt.Error(\"Expected segment completion notification\")\n\t}\n}\n\nfunc TestExecuteSegmentWithTimeout_NonStreaming(t *testing.T) {\n\t// This test verifies that when streaming is disabled,\n\t// trackPendingSegment returns early without tracking when streamingResults is nil\n\tsegment := &config.Segment{\n\t\tType:    \"text\",\n\t\tTimeout: 10,\n\t}\n\n\tengine := &Engine{\n\t\t// streamingResults is nil (non-streaming mode)\n\t}\n\n\tdone := make(chan bool)\n\n\t// Pre-register segment (simulating what happens in concurrent execution)\n\tengine.pendingSegments.Store(segment.Name(), true)\n\n\t// trackPendingSegment should not track when streamingResults is nil\n\tengine.trackPendingSegment(segment, done)\n\n\t// Signal completion\n\tclose(done)\n\n\t// Give time for any goroutine to run (shouldn't be one)\n\ttime.Sleep(50 * time.Millisecond)\n\n\t// Segment should still be in pendingSegments because notifySegmentCompletion\n\t// was never called (trackPendingSegment returns early when streamingResults is nil)\n\t_, exists := engine.pendingSegments.Load(segment.Name())\n\tassert.True(t, exists, \"Segment should remain in pendingSegments when streaming is disabled\")\n}\n\nfunc TestExecuteSegmentWithTimeout_CachedValueFallback(t *testing.T) {\n\t// This test verifies that a pending segment's Text() returns \"...\" placeholder\n\tenv := new(mock.Environment)\n\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\tsegment := &config.Segment{\n\t\tType:     \"text\",\n\t\tPending:  true,\n\t\tTemplate: \"actual content\",\n\t}\n\n\t// Initialize the segment writer\n\terr := segment.MapSegmentWithWriter(env)\n\tassert.NoError(t, err)\n\n\t// Render with pending state - should show \"...\"\n\tsegment.Render(0, true)\n\ttext := segment.Text()\n\tassert.Equal(t, \"...\", text, \"Pending segment should show ...\")\n\n\t// After completion, render again with actual content\n\tsegment.Pending = false\n\tsegment.Render(0, true)\n\ttext = segment.Text()\n\tassert.NotEqual(t, \"...\", text, \"Non-pending segment should show actual content\")\n}\n"
  },
  {
    "path": "src/prompt/status.go",
    "content": "package prompt\n\nfunc (e *Engine) Status() string {\n\te.writePrimaryPrompt(false)\n\treturn e.string()\n}\n"
  },
  {
    "path": "src/prompt/streaming.go",
    "content": "package prompt\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n)\n\n// StreamPrimary returns a channel that yields prompt updates as segments complete.\nfunc (e *Engine) StreamPrimary() <-chan string {\n\t// Initialize streaming infrastructure BEFORE launching goroutine\n\t// This ensures the channel exists when segments start timing out\n\te.streamingResults = make(chan *config.Segment, 100)\n\te.allBlocks = e.Config.Blocks\n\n\tout := make(chan string, 10)\n\n\tgo func() {\n\t\tdefer close(out)\n\t\tdefer close(e.streamingResults)\n\n\t\t// Render and send initial prompt with pending segments\n\t\tinitialPrompt := e.Primary()\n\t\tout <- initialPrompt\n\n\t\tif e.countPendingSegments() == 0 {\n\t\t\treturn\n\t\t}\n\n\t\t// Listen for segment completions\n\t\tfor range e.streamingResults {\n\t\t\tout <- e.renderFromBlocks()\n\n\t\t\tif e.countPendingSegments() == 0 {\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n\n\treturn out\n}\n\n// countPendingSegments counts how many segments are marked as pending\nfunc (e *Engine) countPendingSegments() int {\n\tcount := 0\n\te.pendingSegments.Range(func(_, _ any) bool {\n\t\tcount++\n\t\treturn true\n\t})\n\treturn count\n}\n\n// renderFromBlocks re-renders the complete prompt using stored block data\nfunc (e *Engine) renderFromBlocks() string {\n\t// Reset prompt builder\n\te.prompt.Reset()\n\te.currentLineLength = 0\n\te.activeSegment = nil\n\te.previousActiveSegment = nil\n\te.rprompt = \"\"\n\te.rpromptLength = 0\n\n\treturn e.primaryInternal(true)\n}\n\n// trackPendingSegment continues execution for a timed-out segment in the background\nfunc (e *Engine) trackPendingSegment(segment *config.Segment, done chan bool) {\n\tif e.streamingResults == nil {\n\t\treturn\n\t}\n\n\t// Segment is already pre-registered in pendingSegments map\n\tgo func() {\n\t\t<-done\n\t\tsegment.Pending = false\n\t\te.notifySegmentCompletion(segment)\n\t}()\n}\n\n// notifySegmentCompletion sends completed segment to the streaming results channel\nfunc (e *Engine) notifySegmentCompletion(segment *config.Segment) {\n\tif e.streamingResults == nil {\n\t\treturn\n\t}\n\n\tif _, ok := e.pendingSegments.LoadAndDelete(segment.Name()); ok {\n\t\tselect {\n\t\tcase e.streamingResults <- segment:\n\t\t\t// Successfully notified consumer\n\t\tdefault:\n\t\t\t// Consumer not ready or already exited\n\t\t\t// This can happen if segment completes after consumer finishes\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/prompt/streaming_test.go",
    "content": "package prompt\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestifymock \"github.com/stretchr/testify/mock\"\n\t\"github.com/stretchr/testify/require\"\n)\n\nfunc TestStreamPrimary_NoSegments(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Pwd\").Return(\"/test\")\n\tenv.On(\"Home\").Return(\"/home\")\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{Streaming: true})\n\tenv.On(\"CursorPosition\").Return(1, 1)\n\tenv.On(\"StatusCodes\").Return(0, \"0\")\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\tterminal.Init(shell.PWSH)\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{},\n\t\t},\n\t\tEnv: env,\n\t}\n\n\tout := engine.StreamPrimary()\n\tprompts := collectChannelOutput(out, 100*time.Millisecond)\n\n\t// Should get exactly one prompt (initial) with no pending segments\n\tassert.Len(t, prompts, 1)\n}\n\nfunc TestStreamPrimary_WithPendingSegments(t *testing.T) {\n\tengine := &Engine{\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\tsegment := &config.Segment{\n\t\tType:    \"text\",\n\t\tPending: true,\n\t}\n\n\t// Track as pending\n\tengine.pendingSegments.Store(segment.Name(), true)\n\n\t// Simulate segment completion in background\n\tgo func() {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tsegment.Pending = false\n\t\tengine.notifySegmentCompletion(segment)\n\t}()\n\n\t// Verify notification is received\n\tselect {\n\tcase completed := <-engine.streamingResults:\n\t\tassert.Equal(t, segment, completed)\n\t\tassert.False(t, completed.Pending)\n\tcase <-time.After(200 * time.Millisecond):\n\t\tt.Error(\"Expected segment completion notification\")\n\t}\n}\n\nfunc TestCountPendingSegments(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tSegments []string\n\t\tCount    int\n\t}{\n\t\t{Case: \"No pending segments\", Count: 0, Segments: []string{}},\n\t\t{Case: \"One pending segment\", Count: 1, Segments: []string{\"segment1\"}},\n\t\t{Case: \"Multiple pending segments\", Count: 3, Segments: []string{\"segment1\", \"segment2\", \"segment3\"}},\n\t}\n\n\tfor _, tc := range cases {\n\t\tengine := &Engine{}\n\n\t\tfor _, name := range tc.Segments {\n\t\t\tengine.pendingSegments.Store(name, true)\n\t\t}\n\n\t\tcount := engine.countPendingSegments()\n\t\tassert.Equal(t, tc.Count, count, tc.Case)\n\t}\n}\n\nfunc TestNotifySegmentCompletion(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tStreamingSetup bool\n\t\tSegmentPending bool\n\t\tExpectNotify   bool\n\t}{\n\t\t{Case: \"No streaming channel\", StreamingSetup: false, SegmentPending: true, ExpectNotify: false},\n\t\t{Case: \"Segment not pending\", StreamingSetup: true, SegmentPending: false, ExpectNotify: false},\n\t\t{Case: \"Valid notification\", StreamingSetup: true, SegmentPending: true, ExpectNotify: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tengine := &Engine{}\n\t\tsegment := &config.Segment{Type: \"test\"}\n\n\t\tif tc.StreamingSetup {\n\t\t\tengine.streamingResults = make(chan *config.Segment, 10)\n\t\t}\n\n\t\tif tc.SegmentPending {\n\t\t\tengine.pendingSegments.Store(segment.Name(), true)\n\t\t}\n\n\t\tengine.notifySegmentCompletion(segment)\n\n\t\tif tc.ExpectNotify {\n\t\t\tselect {\n\t\t\tcase received := <-engine.streamingResults:\n\t\t\t\tassert.Equal(t, segment, received, tc.Case)\n\t\t\tcase <-time.After(100 * time.Millisecond):\n\t\t\t\tt.Errorf(\"%s: Expected notification but got timeout\", tc.Case)\n\t\t\t}\n\t\t} else if tc.StreamingSetup {\n\t\t\tselect {\n\t\t\tcase <-engine.streamingResults:\n\t\t\t\tt.Errorf(\"%s: Unexpected notification received\", tc.Case)\n\t\t\tcase <-time.After(50 * time.Millisecond):\n\t\t\t\t// Expected - no notification\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc TestTrackPendingSegment(t *testing.T) {\n\tengine := &Engine{\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\tsegment := &config.Segment{\n\t\tType:    \"test\",\n\t\tPending: true,\n\t}\n\n\tdone := make(chan bool)\n\n\t// Pre-register segment as pending (this happens in writeSegmentsConcurrently in real code)\n\tengine.pendingSegments.Store(segment.Name(), true)\n\n\t// Start tracking\n\tengine.trackPendingSegment(segment, done)\n\n\t// Verify segment is tracked\n\t_, ok := engine.pendingSegments.Load(segment.Name())\n\tassert.True(t, ok, \"Segment should be tracked\")\n\n\t// Simulate completion\n\tclose(done)\n\n\t// Wait for goroutine to process\n\tselect {\n\tcase completed := <-engine.streamingResults:\n\t\tassert.Equal(t, segment, completed)\n\t\tassert.False(t, segment.Pending, \"Segment should no longer be pending\")\n\tcase <-time.After(100 * time.Millisecond):\n\t\tt.Error(\"Expected segment completion notification\")\n\t}\n\n\t// Verify segment is no longer tracked\n\t_, ok = engine.pendingSegments.Load(segment.Name())\n\tassert.False(t, ok, \"Segment should no longer be tracked\")\n}\n\nfunc TestRenderFromBlocks(_ *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t// This test validates that renderFromBlocks properly delegates to primaryInternal\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{},\n\t\t},\n\t\tEnv:       env,\n\t\tallBlocks: []*config.Block{},\n\t}\n\n\t// Just verify it doesn't panic - full integration tested elsewhere\n\t_ = engine.renderFromBlocks()\n}\n\nfunc TestPrimaryInternal_FromCache(_ *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t// This test validates the fromCache parameter is handled correctly\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{},\n\t\t},\n\t\tEnv:       env,\n\t\tallBlocks: []*config.Block{},\n\t}\n\n\t// Just verify it doesn't panic - full integration tested elsewhere\n\t_ = engine.primaryInternal(true)\n}\n\nfunc TestRenderBlockFromCache(t *testing.T) {\n\t// This test validates renderBlockFromCache handles segments correctly\n\tsegment := &config.Segment{\n\t\tType:    \"text\",\n\t\tEnabled: false,\n\t}\n\n\tblock := &config.Block{\n\t\tType:      config.Prompt,\n\t\tAlignment: config.Left,\n\t\tSegments:  []*config.Segment{segment},\n\t}\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{},\n\t}\n\n\tterminal.Init(shell.PWSH)\n\n\t// Should not render when segment is disabled and not forced\n\tresult := engine.renderBlockFromCache(block, false)\n\tassert.False(t, result, \"Block should not render with disabled segment\")\n}\n\nfunc TestSegmentPendingState(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\n\tsegment := &config.Segment{\n\t\tType:     \"text\",\n\t\tPending:  true,\n\t\tTemplate: \"test template\",\n\t}\n\terr := segment.MapSegmentWithWriter(env)\n\trequire.NoError(t, err)\n\n\t// Render with pending state - should show \"...\"\n\tsegment.Render(0, true)\n\ttext := segment.Text()\n\tassert.Equal(t, \"...\", text, \"Pending segment should show ...\")\n\n\t// After completion\n\tsegment.Pending = false\n\tsegment.Render(0, true)\n\ttext = segment.Text()\n\tassert.NotEqual(t, \"...\", text, \"Non-pending segment should show actual content\")\n}\n\n// Helper function to collect all output from a channel with timeout\nfunc collectChannelOutput(ch <-chan string, timeout time.Duration) []string {\n\tvar results []string\n\ttimer := time.NewTimer(timeout)\n\tdefer timer.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase result, ok := <-ch:\n\t\t\tif !ok {\n\t\t\t\treturn results\n\t\t\t}\n\t\t\tresults = append(results, result)\n\t\tcase <-timer.C:\n\t\t\treturn results\n\t\t}\n\t}\n}\n\nfunc TestStreamingWithTimeout(t *testing.T) {\n\tengine := &Engine{\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\tsegment := &config.Segment{\n\t\tType:    \"test\",\n\t\tTimeout: 10,\n\t}\n\n\t// Pre-register segment as pending (this happens in writeSegmentsConcurrently in real code)\n\tengine.pendingSegments.Store(segment.Name(), true)\n\n\t// Test that timeout with streaming enabled marks segment as pending\n\tdone := make(chan bool)\n\n\tgo func() {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tclose(done)\n\t}()\n\n\tengine.trackPendingSegment(segment, done)\n\n\t// Verify pending state\n\t_, isPending := engine.pendingSegments.Load(segment.Name())\n\trequire.True(t, isPending, \"Segment should be pending\")\n\n\t// Wait for completion\n\tselect {\n\tcase <-engine.streamingResults:\n\t\t// Success\n\tcase <-time.After(200 * time.Millisecond):\n\t\tt.Error(\"Timeout waiting for segment completion\")\n\t}\n\n\t// Verify no longer pending\n\t_, isPending = engine.pendingSegments.Load(segment.Name())\n\tassert.False(t, isPending, \"Segment should no longer be pending\")\n}\n\nfunc setupStreamingTestEnv() *mock.Environment {\n\tenv := new(mock.Environment)\n\tenv.On(\"Pwd\").Return(\"/test\")\n\tenv.On(\"Home\").Return(\"/home\")\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{Streaming: true})\n\tenv.On(\"CursorPosition\").Return(1, 1)\n\tenv.On(\"StatusCodes\").Return(0, \"0\")\n\tenv.On(\"DirMatchesOneOf\", testifymock.Anything, testifymock.Anything).Return(false)\n\t// Mock accent color retrieval for both Windows and macOS\n\tenv.On(\"RunCommand\", testifymock.Anything, testifymock.Anything, testifymock.Anything, testifymock.Anything).Return(\"4\", nil)\n\tenv.On(\"WindowsRegistryKeyValue\", testifymock.Anything).Return(&runtime.WindowsRegistryValue{ValueType: runtime.DWORD, DWord: 0xFF0078D7}, nil)\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\tterminal.Init(shell.PWSH)\n\tterminal.Colors = color.MakeColors(nil, false, \"\", env)\n\n\treturn env\n}\n\nfunc TestStreamPrimary_FullFlow_WithRendering(t *testing.T) {\n\tenv := setupStreamingTestEnv()\n\n\t// Create segments with different speeds\n\tfastSegment := &config.Segment{\n\t\tType:       \"text\",\n\t\tTemplate:   \"FAST\",\n\t\tForeground: \"#ffffff\",\n\t\tBackground: \"#000000\",\n\t}\n\n\tslowSegment := &config.Segment{\n\t\tType:       \"text\",\n\t\tTemplate:   \"SLOW\",\n\t\tPending:    true, // Initially pending\n\t\tForeground: \"#ffffff\",\n\t\tBackground: \"#000000\",\n\t}\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{\n\t\t\t\t{\n\t\t\t\t\tType:      config.Prompt,\n\t\t\t\t\tAlignment: config.Left,\n\t\t\t\t\tSegments:  []*config.Segment{fastSegment, slowSegment},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tEnv:              env,\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\t// Map segment writers\n\terr := fastSegment.MapSegmentWithWriter(env)\n\trequire.NoError(t, err)\n\terr = slowSegment.MapSegmentWithWriter(env)\n\trequire.NoError(t, err)\n\n\t// Track slow segment as pending\n\tengine.pendingSegments.Store(slowSegment.Name(), true)\n\n\t// Start streaming\n\tout := engine.StreamPrimary()\n\n\t// Simulate slow segment completion after delay\n\tgo func() {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tslowSegment.Pending = false\n\t\tengine.notifySegmentCompletion(slowSegment)\n\t}()\n\n\t// Collect all prompts\n\tprompts := collectChannelOutput(out, 200*time.Millisecond)\n\n\t// Should have at least 2 prompts: initial (with \"...\") and final (with \"SLOW\")\n\tassert.GreaterOrEqual(t, len(prompts), 1, \"Should have at least initial prompt\")\n\n\t// First prompt should contain \"...\" for pending segment\n\tif len(prompts) > 0 {\n\t\tassert.Contains(t, prompts[0], \"...\", \"Initial prompt should show pending text\")\n\t}\n\n\t// If we got multiple prompts, last one should not have \"...\"\n\tif len(prompts) > 1 {\n\t\tassert.NotContains(t, prompts[len(prompts)-1], \"...\", \"Final prompt should not show pending text\")\n\t}\n}\n\nfunc TestStreamPrimary_MultipleBlocks_MixedSpeed(t *testing.T) {\n\tenv := setupStreamingTestEnv()\n\n\t// Block 1: Fast segment\n\tfast1 := &config.Segment{\n\t\tType:     \"text\",\n\t\tTemplate: \"FAST1\",\n\t}\n\n\t// Block 2: Slow segment\n\tslow1 := &config.Segment{\n\t\tType:     \"text\",\n\t\tTemplate: \"SLOW1\",\n\t\tPending:  true,\n\t}\n\n\t// Block 3: Another fast segment\n\tfast2 := &config.Segment{\n\t\tType:     \"text\",\n\t\tTemplate: \"FAST2\",\n\t}\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{\n\t\t\t\t{Type: config.Prompt, Alignment: config.Left, Segments: []*config.Segment{fast1}},\n\t\t\t\t{Type: config.Prompt, Alignment: config.Left, Segments: []*config.Segment{slow1}},\n\t\t\t\t{Type: config.Prompt, Alignment: config.Left, Segments: []*config.Segment{fast2}},\n\t\t\t},\n\t\t},\n\t\tEnv:              env,\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\t// Map segments\n\trequire.NoError(t, fast1.MapSegmentWithWriter(env))\n\trequire.NoError(t, slow1.MapSegmentWithWriter(env))\n\trequire.NoError(t, fast2.MapSegmentWithWriter(env))\n\n\t// Track slow segment\n\tengine.pendingSegments.Store(slow1.Name(), true)\n\n\t// Start streaming\n\tout := engine.StreamPrimary()\n\n\t// Simulate completion\n\tgo func() {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tslow1.Pending = false\n\t\tengine.notifySegmentCompletion(slow1)\n\t}()\n\n\tprompts := collectChannelOutput(out, 200*time.Millisecond)\n\n\t// Should receive prompts\n\tassert.NotEmpty(t, prompts, \"Should receive streaming prompts\")\n}\n\nfunc setupBasicStreamingTestEnv() *Engine {\n\tenv := new(mock.Environment)\n\tenv.On(\"Pwd\").Return(\"/test\")\n\tenv.On(\"Home\").Return(\"/home\")\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{Streaming: true})\n\tenv.On(\"CursorPosition\").Return(1, 1)\n\tenv.On(\"StatusCodes\").Return(0, \"0\")\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\tterminal.Init(shell.PWSH)\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{},\n\t\t},\n\t\tEnv: env,\n\t}\n\n\treturn engine\n}\n\nfunc TestStreamPrimary_EarlyChannelClosure(t *testing.T) {\n\tengine := setupBasicStreamingTestEnv()\n\n\t// Start streaming with no pending segments\n\t// The goroutine should complete quickly and close channels properly\n\tout := engine.StreamPrimary()\n\n\t// Should be able to read from output channel without panic\n\tprompts := collectChannelOutput(out, 100*time.Millisecond)\n\n\t// Should get exactly one prompt (initial) with no pending segments\n\tassert.Len(t, prompts, 1, \"Should receive initial prompt\")\n}\n\nfunc TestStreamPrimary_NoStreamingResults_Channel(t *testing.T) {\n\tengine := setupBasicStreamingTestEnv()\n\n\t// Engine without streamingResults channel (edge case)\n\t// No streamingResults channel set\n\n\t// Should not panic\n\tout := engine.StreamPrimary()\n\tprompts := collectChannelOutput(out, 100*time.Millisecond)\n\n\tassert.Len(t, prompts, 1, \"Should get exactly one prompt with no pending segments\")\n}\n\n// TestStreamPrimary_RaceConditionFix validates that the streaming loop\n// correctly handles segments that complete after Primary() but before/during\n// the counting phase. This tests the fix for the race where pendingCount\n// could get out of sync with actual pending segments.\nfunc TestStreamPrimary_RaceConditionFix(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Pwd\").Return(\"/test\")\n\tenv.On(\"Home\").Return(\"/home\")\n\tenv.On(\"Shell\").Return(shell.PWSH)\n\tenv.On(\"Flags\").Return(&runtime.Flags{Streaming: true})\n\tenv.On(\"CursorPosition\").Return(1, 1)\n\tenv.On(\"StatusCodes\").Return(0, \"0\")\n\n\ttemplate.Cache = &cache.Template{\n\t\tSegments: maps.NewConcurrent[any](),\n\t}\n\ttemplate.Init(env, nil, nil)\n\tterminal.Init(shell.PWSH)\n\n\tengine := &Engine{\n\t\tConfig: &config.Config{\n\t\t\tBlocks: []*config.Block{},\n\t\t},\n\t\tEnv:              env,\n\t\tstreamingResults: make(chan *config.Segment, 10),\n\t}\n\n\t// Create three segments, simulating the race scenario:\n\t// - segmentA: Completes quickly after Primary()\n\t// - segmentB: Completes during loop\n\t// - segmentC: Completes last\n\tsegmentA := &config.Segment{Type: \"test-a\", Pending: true}\n\tsegmentB := &config.Segment{Type: \"test-b\", Pending: true}\n\tsegmentC := &config.Segment{Type: \"test-c\", Pending: true}\n\n\t// Pre-register all three as pending (simulates timeout during Primary())\n\tengine.pendingSegments.Store(segmentA.Name(), true)\n\tengine.pendingSegments.Store(segmentB.Name(), true)\n\tengine.pendingSegments.Store(segmentC.Name(), true)\n\n\t// Simulate segmentA completing immediately after Primary() but before countPendingSegments()\n\t// This is the race condition - notification sent but segment removed from map\n\tgo func() {\n\t\t// Small delay to ensure StreamPrimary has been called but before counting\n\t\ttime.Sleep(5 * time.Millisecond)\n\t\tsegmentA.Pending = false\n\t\tengine.notifySegmentCompletion(segmentA)\n\t}()\n\n\t// Simulate segmentB and segmentC completing during the loop\n\tgo func() {\n\t\ttime.Sleep(30 * time.Millisecond)\n\t\tsegmentB.Pending = false\n\t\tengine.notifySegmentCompletion(segmentB)\n\t}()\n\n\tgo func() {\n\t\ttime.Sleep(50 * time.Millisecond)\n\t\tsegmentC.Pending = false\n\t\tengine.notifySegmentCompletion(segmentC)\n\t}()\n\n\t// Start streaming\n\tout := engine.StreamPrimary()\n\n\t// Collect all prompts with sufficient timeout\n\tprompts := collectChannelOutput(out, 200*time.Millisecond)\n\n\t// With the fix, we should receive updates for all three segments\n\t// Initial prompt + 3 updates (A, B, C) = 4 total\n\t// Without the fix, we might only get Initial + 2 updates and exit early\n\tassert.GreaterOrEqual(t, len(prompts), 3, \"Should receive updates for all pending segments\")\n\n\t// Verify all segments were properly cleaned up\n\tcount := engine.countPendingSegments()\n\tassert.Equal(t, 0, count, \"All pending segments should be cleared\")\n}\n"
  },
  {
    "path": "src/prompt/tooltip.go",
    "content": "package prompt\n\nimport (\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/config\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/terminal\"\n)\n\nfunc (e *Engine) Tooltip(tip string) string {\n\ttip = strings.Trim(tip, \" \")\n\ttooltips := make([]*config.Segment, 0, 1)\n\n\tfor _, tooltip := range e.Config.Tooltips {\n\t\tif !slices.Contains(tooltip.Tips, tip) {\n\t\t\tcontinue\n\t\t}\n\n\t\ttooltip.Execute(e.Env)\n\n\t\tif !tooltip.Enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\ttooltips = append(tooltips, tooltip)\n\t}\n\n\tif len(tooltips) == 0 {\n\t\treturn \"\"\n\t}\n\n\t// little hack to reuse the current logic\n\tblock := &config.Block{\n\t\tAlignment: config.Right,\n\t\tSegments:  tooltips,\n\t}\n\n\ttext, length := e.writeBlockSegments(block)\n\n\t// do not print anything when we don't have any text\n\tif length == 0 {\n\t\treturn \"\"\n\t}\n\n\ttext, length = e.handleToolTipAction(text, length)\n\n\tswitch e.Env.Shell() {\n\tcase shell.PWSH:\n\t\te.rprompt = text\n\t\te.currentLineLength = e.Env.Flags().Column\n\n\t\tspace, ok := e.canWriteRightBlock(length, true)\n\t\tif !ok {\n\t\t\treturn \"\"\n\t\t}\n\n\t\te.write(terminal.SaveCursorPosition())\n\t\te.write(strings.Repeat(\" \", space))\n\t\te.write(text)\n\t\te.write(terminal.RestoreCursorPosition())\n\t\treturn e.string()\n\tdefault:\n\t\treturn text\n\t}\n}\n\nfunc (e *Engine) handleToolTipAction(text string, length int) (string, int) {\n\tif e.Config.ToolTipsAction.IsDefault() {\n\t\treturn text, length\n\t}\n\n\trprompt, OK := cache.Get[string](cache.Session, RPromptKey)\n\tif !OK {\n\t\treturn text, length\n\t}\n\n\trpromptLength, OK := cache.Get[int](cache.Session, RPromptLengthKey)\n\tif !OK {\n\t\treturn text, length\n\t}\n\n\tlength += rpromptLength\n\n\tswitch e.Config.ToolTipsAction {\n\tcase config.Extend:\n\t\ttext = rprompt + text\n\tcase config.Prepend:\n\t\ttext += rprompt\n\t}\n\n\treturn text, length\n}\n"
  },
  {
    "path": "src/regex/regex.go",
    "content": "package regex\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nvar (\n\tregexCache     = make(map[string]*regexp.Regexp)\n\tregexCacheLock = sync.RWMutex{}\n)\n\nconst (\n\tLINK = `(?P<STR>\\x1b]8;;(.+)\\x1b\\\\(?P<TEXT>.+)\\x1b]8;;\\x1b\\\\)`\n)\n\nfunc GetCompiledRegex(pattern string) (*regexp.Regexp, error) {\n\t// try in cache first\n\tregexCacheLock.RLock()\n\tre := regexCache[pattern]\n\tregexCacheLock.RUnlock()\n\tif re != nil {\n\t\treturn re, nil\n\t}\n\n\t// should we panic or return the error?\n\tre, err := regexp.Compile(pattern)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\t// lock for concurrent access and save the compiled expression in cache\n\tregexCacheLock.Lock()\n\tregexCache[pattern] = re\n\tregexCacheLock.Unlock()\n\n\treturn re, nil\n}\n\nfunc FindNamedRegexMatch(pattern, text string) map[string]string {\n\tresult := make(map[string]string)\n\n\tre, err := GetCompiledRegex(pattern)\n\tif err != nil {\n\t\treturn result\n\t}\n\n\tmatch := re.FindStringSubmatch(text)\n\tif len(match) == 0 {\n\t\treturn result\n\t}\n\n\tfor i, name := range re.SubexpNames() {\n\t\tif i == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tresult[name] = match[i]\n\t}\n\n\treturn result\n}\n\nfunc FindAllNamedRegexMatch(pattern, text string) []map[string]string {\n\tvar results []map[string]string\n\n\tre, err := GetCompiledRegex(pattern)\n\tif err != nil {\n\t\treturn results\n\t}\n\n\tmatch := re.FindAllStringSubmatch(text, -1)\n\n\tif len(match) == 0 {\n\t\treturn results\n\t}\n\n\tfor _, set := range match {\n\t\tresult := make(map[string]string)\n\t\tfor i, name := range re.SubexpNames() {\n\t\t\tif i == 0 {\n\t\t\t\tresult[\"text\"] = set[i]\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresult[name] = set[i]\n\t\t}\n\t\tresults = append(results, result)\n\t}\n\n\treturn results\n}\n\nfunc ReplaceAllString(pattern, text, replaceText string) string {\n\tre, err := GetCompiledRegex(pattern)\n\tif err != nil {\n\t\treturn text\n\t}\n\n\treturn re.ReplaceAllString(text, replaceText)\n}\n\nfunc MatchString(pattern, text string) bool {\n\tre, err := GetCompiledRegex(pattern)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn re.MatchString(text)\n}\n\nfunc FindStringMatch(pattern, text string, index int) (string, bool) {\n\tre, err := GetCompiledRegex(pattern)\n\tif err != nil {\n\t\treturn text, false\n\t}\n\n\tmatches := re.FindStringSubmatch(text)\n\tif len(matches) <= index {\n\t\treturn text, false\n\t}\n\n\tmatch := matches[index]\n\tif len(match) == 0 {\n\t\treturn text, false\n\t}\n\n\treturn match, true\n}\n"
  },
  {
    "path": "src/regex/regex_test.go",
    "content": "package regex\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFindStringMatch(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tPattern  string\n\t\tText     string\n\t\tExpected string\n\t\tIndex    int\n\t}{\n\t\t{\n\t\t\tCase:     \"Full match at index 0\",\n\t\t\tPattern:  `\\w+`,\n\t\t\tText:     \"hello\",\n\t\t\tIndex:    0,\n\t\t\tExpected: \"hello\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Capture group at index 1\",\n\t\t\tPattern:  `hello (\\w+)`,\n\t\t\tText:     \"hello world\",\n\t\t\tIndex:    1,\n\t\t\tExpected: \"world\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"No matches returns original text\",\n\t\t\tPattern:  `\\d+`,\n\t\t\tText:     \"hello\",\n\t\t\tIndex:    0,\n\t\t\tExpected: \"hello\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Invalid pattern returns original text\",\n\t\t\tPattern:  `[invalid`,\n\t\t\tText:     \"hello\",\n\t\t\tIndex:    0,\n\t\t\tExpected: \"hello\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Empty text returns empty string\",\n\t\t\tPattern:  `\\w+`,\n\t\t\tText:     \"\",\n\t\t\tIndex:    0,\n\t\t\tExpected: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Index out of bounds returns original text\",\n\t\t\tPattern:  `(\\w+)`,\n\t\t\tText:     \"hello\",\n\t\t\tIndex:    2,\n\t\t\tExpected: \"hello\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Multiple capture groups\",\n\t\t\tPattern:  `(\\w+)\\s(\\w+)`,\n\t\t\tText:     \"hello world\",\n\t\t\tIndex:    2,\n\t\t\tExpected: \"world\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tgot, _ := FindStringMatch(tc.Pattern, tc.Text, tc.Index)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/runtime/battery/battery.go",
    "content": "// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\ntype Info struct {\n\tPercentage int\n\tState      State\n}\n\ntype NoBatteryError struct{}\n\nfunc (m *NoBatteryError) Error() string {\n\treturn \"no battery\"\n}\n\n// State type enumerates possible battery states.\ntype State int\n\nvar states = [...]string{\n\tUnknown:     \"Unknown\",\n\tEmpty:       \"Empty\",\n\tFull:        \"Full\",\n\tCharging:    \"Charging\",\n\tDischarging: \"Discharging\",\n\tNotCharging: \"Not Charging\",\n}\n\nfunc (s State) String() string {\n\treturn states[s]\n}\n\n// Possible state values.\n// Unknown can mean either controller returned unknown, or\n// not able to retrieve state due to some error.\nconst (\n\tUnknown State = iota\n\tEmpty\n\tFull\n\tCharging\n\tDischarging\n\tNotCharging\n)\n"
  },
  {
    "path": "src/runtime/battery/battery_darwin.go",
    "content": "package battery\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n)\n\nfunc mapMostLogicalState(state string) State {\n\tswitch state {\n\tcase \"charging\":\n\t\treturn Charging\n\tcase \"discharging\":\n\t\treturn Discharging\n\tcase \"AC attached\":\n\t\treturn NotCharging\n\tcase \"full\":\n\t\treturn Full\n\tcase \"empty\":\n\t\treturn Empty\n\tcase \"charged\":\n\t\treturn Full\n\tdefault:\n\t\treturn Unknown\n\t}\n}\n\nfunc parseBatteryOutput(output string) (*Info, error) {\n\tmatches := regex.FindNamedRegexMatch(`(?P<PERCENTAGE>[0-9]{1,3})%; (?P<STATE>[a-zA-Z\\s]+);`, output)\n\tif len(matches) != 2 {\n\t\treturn nil, errors.New(\"unable to find battery state based on output\")\n\t}\n\n\tvar percentage int\n\tvar err error\n\tif percentage, err = strconv.Atoi(matches[\"PERCENTAGE\"]); err != nil {\n\t\treturn nil, errors.New(\"unable to parse battery percentage\")\n\t}\n\n\t// sometimes it reports discharging when at 100, so let's force it to Full\n\t// https://github.com/JanDeDobbeleer/oh-my-posh/issues/3729\n\tif percentage == 100 {\n\t\treturn &Info{\n\t\t\tPercentage: percentage,\n\t\t\tState:      Full,\n\t\t}, nil\n\t}\n\n\treturn &Info{\n\t\tPercentage: percentage,\n\t\tState:      mapMostLogicalState(matches[\"STATE\"]),\n\t}, nil\n}\n\nfunc Get() (*Info, error) {\n\toutput, err := cmd.Run(\"pmset\", \"-g\", \"batt\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !strings.Contains(output, \"Battery\") {\n\t\treturn nil, ErrNotFound\n\t}\n\treturn parseBatteryOutput(output)\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_darwin_test.go",
    "content": "package battery\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseBatteryOutput(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tOutput             string\n\t\tExpectedState      State\n\t\tExpectedPercentage int\n\t\tExpectError        bool\n\t}{\n\t\t{\n\t\t\tCase:               \"charging\",\n\t\t\tOutput:             \"99%; charging;\",\n\t\t\tExpectedState:      Charging,\n\t\t\tExpectedPercentage: 99,\n\t\t},\n\t\t{\n\t\t\tCase:               \"charging 1%\",\n\t\t\tOutput:             \"1%; charging;\",\n\t\t\tExpectedState:      Charging,\n\t\t\tExpectedPercentage: 1,\n\t\t},\n\t\t{\n\t\t\tCase:               \"not charging 80%\",\n\t\t\tOutput:             \"81%; AC attached;\",\n\t\t\tExpectedState:      NotCharging,\n\t\t\tExpectedPercentage: 81,\n\t\t},\n\t\t{\n\t\t\tCase:               \"charged\",\n\t\t\tOutput:             \"100%; charged;\",\n\t\t\tExpectedState:      Full,\n\t\t\tExpectedPercentage: 100,\n\t\t},\n\t\t{\n\t\t\tCase:               \"discharging, but not\",\n\t\t\tOutput:             \"100%; discharging;\",\n\t\t\tExpectedState:      Full,\n\t\t\tExpectedPercentage: 100,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tinfo, err := parseBatteryOutput(tc.Output)\n\t\tif tc.ExpectError {\n\t\t\tassert.Error(t, err, tc.Case)\n\t\t\treturn\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedState, info.State, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedPercentage, info.Percentage, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_linux.go",
    "content": "// battery\n// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst sysfs = \"/sys/class/power_supply\"\n\nfunc newState(name string) (State, error) {\n\tfor i, state := range states {\n\t\tif strings.EqualFold(name, state) {\n\t\t\treturn State(i), nil\n\t\t}\n\t}\n\n\treturn Unknown, fmt.Errorf(\"invalid state `%s`\", name)\n}\n\nfunc readFloat(path, filename string) (float64, error) {\n\tstr, err := os.ReadFile(filepath.Join(path, filename))\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tif len(str) == 0 {\n\t\treturn 0, ErrNotFound\n\t}\n\n\tnum, err := strconv.ParseFloat(string(str[:len(str)-1]), 64)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn num / 1000, nil // Convert micro->milli\n}\n\nfunc readAmp(path, filename string, volts float64) (float64, error) {\n\tval, err := readFloat(path, filename)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\treturn val * volts, nil\n}\n\nfunc isBattery(path string) bool {\n\tt, err := os.ReadFile(filepath.Join(path, \"type\"))\n\treturn err == nil && string(t) == \"Battery\\n\"\n}\n\nfunc getBatteryFiles() ([]string, error) {\n\tfiles, err := os.ReadDir(sysfs)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar bFiles []string\n\tfor _, file := range files {\n\t\tpath := filepath.Join(sysfs, file.Name())\n\t\tif isBattery(path) {\n\t\t\tbFiles = append(bFiles, path)\n\t\t}\n\t}\n\n\tif len(bFiles) == 0 {\n\t\treturn nil, &NoBatteryError{}\n\t}\n\n\treturn bFiles, nil\n}\n\nfunc getByPath(path string) (*battery, error) {\n\tb := &battery{}\n\tvar err error\n\n\tif b.Current, err = readFloat(path, \"energy_now\"); err == nil {\n\t\tif b.Full, err = readFloat(path, \"energy_full\"); err != nil {\n\t\t\treturn nil, errors.New(\"unable to parse energy_full\")\n\t\t}\n\t} else {\n\t\tcurrentDoesNotExist := os.IsNotExist(err)\n\t\tif b.Voltage, err = readFloat(path, \"voltage_now\"); err != nil {\n\t\t\treturn nil, errors.New(\"unable to parse voltage_now\")\n\t\t}\n\t\tb.Voltage /= 1000\n\t\tif currentDoesNotExist {\n\t\t\tif b.Current, err = readAmp(path, \"charge_now\", b.Voltage); err != nil {\n\t\t\t\treturn nil, errors.New(\"unable to parse charge_now\")\n\t\t\t}\n\t\t\tif b.Full, err = readAmp(path, \"charge_full\", b.Voltage); err != nil {\n\t\t\t\treturn nil, errors.New(\"unable to parse charge_full\")\n\t\t\t}\n\t\t} else {\n\t\t\tif b.Full, err = readFloat(path, \"energy_full\"); err != nil {\n\t\t\t\treturn nil, errors.New(\"unable to parse energy_full\")\n\t\t\t}\n\t\t}\n\t}\n\n\tstate, err := os.ReadFile(filepath.Join(path, \"status\"))\n\tif err != nil || len(state) == 0 {\n\t\treturn nil, errors.New(\"unable to parse or invalid status\")\n\t}\n\tif b.State, err = newState(string(state[:len(state)-1])); err != nil {\n\t\treturn nil, errors.New(\"unable to map to new state\")\n\t}\n\n\treturn b, nil\n}\n\nfunc systemGetAll() ([]*battery, error) {\n\tbFiles, err := getBatteryFiles()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar batteries []*battery\n\tvar errs Errors\n\n\tfor _, bFile := range bFiles {\n\t\tb, err := getByPath(bFile)\n\t\tif err != nil {\n\t\t\terrs = append(errs, err)\n\t\t\tcontinue\n\t\t}\n\t\tbatteries = append(batteries, b)\n\t}\n\n\tif len(batteries) == 0 {\n\t\treturn nil, errs\n\t}\n\n\treturn batteries, nil\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_netbsd.go",
    "content": "package battery\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n)\n\nfunc Get() (*Info, error) {\n\toutput, err := cmd.Run(\"envstat\", \"-s\", \"acpibat0:charge\", \"-n\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tpercentage, err := strconv.Atoi(strings.TrimSpace(output))\n\tif err != nil {\n\t\treturn nil, errors.New(\"unable to parse battery percentage\")\n\t}\n\treturn &Info{\n\t\tPercentage: percentage,\n\t\tState:      Unknown,\n\t}, nil\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_openandfreebsd.go",
    "content": "//go:build openbsd || freebsd\n\npackage battery\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n)\n\n// See https://man.openbsd.org/man8/apm.8\nfunc mapMostLogicalState(state string) State {\n\tswitch state {\n\tcase \"3\":\n\t\treturn Charging\n\tcase \"0\", \"1\":\n\t\treturn Discharging\n\tcase \"2\":\n\t\treturn Empty\n\tdefault:\n\t\treturn Unknown\n\t}\n}\n\nfunc parseBatteryOutput(apm_percentage string, apm_status string) (*Info, error) {\n\tpercentage, err := strconv.Atoi(strings.TrimSpace(apm_percentage))\n\tif err != nil {\n\t\treturn nil, errors.New(\"unable to parse battery percentage\")\n\t}\n\n\tif percentage == 100 {\n\t\treturn &Info{\n\t\t\tPercentage: percentage,\n\t\t\tState:      Full,\n\t\t}, nil\n\t}\n\n\treturn &Info{\n\t\tPercentage: percentage,\n\t\tState:      mapMostLogicalState(apm_status),\n\t}, nil\n}\n\nfunc Get() (*Info, error) {\n\tapm_percentage, err := cmd.Run(\"apm\", \"-l\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tapm_status, err := cmd.Run(\"apm\", \"-b\")\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn parseBatteryOutput(apm_percentage, apm_status)\n\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_openandfreebsd_test.go",
    "content": "//go:build openbsd || freebsd\n\npackage battery\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestParseBatteryOutput(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tPercentOutput      string\n\t\tStatusOutput       string\n\t\tExpectedState      State\n\t\tExpectedPercentage int\n\t\tExpectError        bool\n\t}{\n\t\t{\n\t\t\tCase:               \"charging\",\n\t\t\tPercentOutput:      \"99\",\n\t\t\tStatusOutput:       \"3\",\n\t\t\tExpectedState:      Charging,\n\t\t\tExpectedPercentage: 99,\n\t\t},\n\t\t{\n\t\t\tCase:               \"charging 1%\",\n\t\t\tPercentOutput:      \"1\",\n\t\t\tStatusOutput:       \"3\",\n\t\t\tExpectedState:      Charging,\n\t\t\tExpectedPercentage: 1,\n\t\t},\n\t\t{\n\t\t\tCase:               \"removed\",\n\t\t\tPercentOutput:      \"0\",\n\t\t\tStatusOutput:       \"4\",\n\t\t\tExpectedState:      Unknown,\n\t\t\tExpectedPercentage: 0,\n\t\t},\n\t\t{\n\t\t\tCase:               \"charged\",\n\t\t\tPercentOutput:      \"100\",\n\t\t\tStatusOutput:       \"0\",\n\t\t\tExpectedState:      Full,\n\t\t\tExpectedPercentage: 100,\n\t\t},\n\t\t{\n\t\t\tCase:               \"discharging\",\n\t\t\tPercentOutput:      \"25\",\n\t\t\tStatusOutput:       \"1\",\n\t\t\tExpectedState:      Discharging,\n\t\t\tExpectedPercentage: 25,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tinfo, err := parseBatteryOutput(tc.PercentOutput, tc.StatusOutput)\n\t\tif tc.ExpectError {\n\t\t\tassert.Error(t, err, tc.Case)\n\t\t\treturn\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedState, info.State, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedPercentage, info.Percentage, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_windows.go",
    "content": "// battery\n// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\nimport (\n\t\"errors\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\ntype batteryQueryInformation struct {\n\tBatteryTag       uint32\n\tInformationLevel int32\n\tAtRate           int32\n}\n\ntype batteryInformation struct {\n\tCapabilities        uint32\n\tTechnology          uint8\n\tReserved            [3]uint8\n\tChemistry           [4]uint8\n\tDesignedCapacity    uint32\n\tFullChargedCapacity uint32\n\tDefaultAlert1       uint32\n\tDefaultAlert2       uint32\n\tCriticalBias        uint32\n\tCycleCount          uint32\n}\n\ntype batteryWaitStatus struct {\n\tBatteryTag   uint32\n\tTimeout      uint32\n\tPowerState   uint32\n\tLowCapacity  uint32\n\tHighCapacity uint32\n}\n\ntype batteryStatus struct {\n\tPowerState uint32\n\tCapacity   uint32\n\tVoltage    uint32\n\tRate       int32\n}\n\ntype guid struct {\n\tData1 uint32\n\tData2 uint16\n\tData3 uint16\n\tData4 [8]byte\n}\n\ntype spDeviceInterfaceData struct {\n\tcbSize             uint32\n\tInterfaceClassGuid guid\n\tFlags              uint32\n\tReserved           uint\n}\n\nvar guidDeviceBattery = guid{\n\t0x72631e54,\n\t0x78A4,\n\t0x11d0,\n\t[8]byte{0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a},\n}\n\nfunc uint32ToFloat64(num uint32) (float64, error) {\n\tif num == 0xffffffff { // BATTERY_UNKNOWN_CAPACITY\n\t\treturn 0, errors.New(\"unknown value received\")\n\t}\n\treturn float64(num), nil\n}\n\nfunc setupDiSetup(proc *windows.LazyProc, args ...uintptr) (uintptr, error) {\n\tr1, _, errno := syscall.SyscallN(proc.Addr(), args...)\n\tif windows.Handle(r1) == windows.InvalidHandle {\n\t\tif errno != 0 {\n\t\t\treturn 0, error(errno)\n\t\t}\n\t\treturn 0, syscall.EINVAL\n\t}\n\treturn r1, nil\n}\n\nfunc setupDiCall(proc *windows.LazyProc, args ...uintptr) syscall.Errno {\n\tr1, _, errno := syscall.SyscallN(proc.Addr(), args...)\n\tif r1 == 0 {\n\t\tif errno != 0 {\n\t\t\treturn errno\n\t\t}\n\t\treturn syscall.EINVAL\n\t}\n\treturn 0\n}\n\nvar setupapi = &windows.LazyDLL{Name: \"setupapi.dll\", System: true}\nvar setupDiGetClassDevsW = setupapi.NewProc(\"SetupDiGetClassDevsW\")\nvar setupDiEnumDeviceInterfaces = setupapi.NewProc(\"SetupDiEnumDeviceInterfaces\")\nvar setupDiGetDeviceInterfaceDetailW = setupapi.NewProc(\"SetupDiGetDeviceInterfaceDetailW\")\nvar setupDiDestroyDeviceInfoList = setupapi.NewProc(\"SetupDiDestroyDeviceInfoList\")\n\nfunc readState(powerState uint32) State {\n\tswitch {\n\tcase powerState&0x00000004 != 0:\n\t\treturn Charging\n\tcase powerState&0x00000008 != 0:\n\t\treturn Empty\n\tcase powerState&0x00000002 != 0:\n\t\treturn Discharging\n\tcase powerState&0x00000001 != 0:\n\t\treturn Full\n\tdefault:\n\t\treturn Unknown\n\t}\n}\n\nfunc systemGet(idx int) (*battery, error) {\n\thdev, err := setupDiSetup(\n\t\tsetupDiGetClassDevsW,\n\t\tuintptr(unsafe.Pointer(&guidDeviceBattery)),\n\t\t0,\n\t\t0,\n\t\t2|16, // DIGCF_PRESENT|DIGCF_DEVICEINTERFACE\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer func() {\n\t\t_, _, _ = syscall.SyscallN(setupDiDestroyDeviceInfoList.Addr(), hdev)\n\t}()\n\n\tvar did spDeviceInterfaceData\n\tdid.cbSize = uint32(unsafe.Sizeof(did))\n\terrno := setupDiCall(\n\t\tsetupDiEnumDeviceInterfaces,\n\t\thdev,\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&guidDeviceBattery)),\n\t\tuintptr(idx),\n\t\tuintptr(unsafe.Pointer(&did)),\n\t)\n\n\tif errno == 259 { // ERROR_NO_MORE_ITEMS\n\t\treturn nil, ErrNotFound\n\t}\n\n\tif errno != 0 {\n\t\treturn nil, errno\n\t}\n\n\tvar cbRequired uint32\n\terrno = setupDiCall(\n\t\tsetupDiGetDeviceInterfaceDetailW,\n\t\thdev,\n\t\tuintptr(unsafe.Pointer(&did)),\n\t\t0,\n\t\t0,\n\t\tuintptr(unsafe.Pointer(&cbRequired)),\n\t\t0,\n\t)\n\n\tif errno != 0 && errno != 122 { // ERROR_INSUFFICIENT_BUFFER\n\t\treturn nil, errno\n\t}\n\n\tif cbRequired == 0 {\n\t\treturn nil, errors.New(\"no buffer information returned\")\n\t}\n\n\t// The god damn struct with ANYSIZE_ARRAY of utf16 in it is crazy.\n\t// So... let's emulate it with array of uint16 ;-D.\n\t// Keep in mind that the first two elements are actually cbSize.\n\tdidd := make([]uint16, cbRequired/2)\n\tcbSize := (*uint32)(unsafe.Pointer(&didd[0]))\n\tif unsafe.Sizeof(uint(0)) == 8 {\n\t\t*cbSize = 8\n\t} else {\n\t\t*cbSize = 6\n\t}\n\n\terrno = setupDiCall(\n\t\tsetupDiGetDeviceInterfaceDetailW,\n\t\thdev,\n\t\tuintptr(unsafe.Pointer(&did)),\n\t\tuintptr(unsafe.Pointer(&didd[0])),\n\t\tuintptr(cbRequired),\n\t\tuintptr(unsafe.Pointer(&cbRequired)),\n\t\t0,\n\t)\n\n\tif errno != 0 {\n\t\treturn nil, errno\n\t}\n\n\tdevicePath := &didd[2:][0]\n\n\thandle, err := windows.CreateFile(\n\t\tdevicePath,\n\t\twindows.GENERIC_READ|windows.GENERIC_WRITE,\n\t\twindows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE,\n\t\tnil,\n\t\twindows.OPEN_EXISTING,\n\t\twindows.FILE_ATTRIBUTE_NORMAL,\n\t\t0,\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdefer func() {\n\t\t_ = windows.CloseHandle(handle)\n\t}()\n\n\tvar dwOut uint32\n\n\tvar dwWait uint32\n\tvar bqi batteryQueryInformation\n\terr = windows.DeviceIoControl(\n\t\thandle,\n\t\t2703424, // IOCTL_BATTERY_QUERY_TAG\n\t\t(*byte)(unsafe.Pointer(&dwWait)),\n\t\tuint32(unsafe.Sizeof(dwWait)),\n\t\t(*byte)(unsafe.Pointer(&bqi.BatteryTag)),\n\t\tuint32(unsafe.Sizeof(bqi.BatteryTag)),\n\t\t&dwOut,\n\t\tnil,\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif bqi.BatteryTag == 0 {\n\t\treturn nil, errors.New(\"battery tag not returned\")\n\t}\n\n\tb := &battery{}\n\n\tvar bi batteryInformation\n\terr = windows.DeviceIoControl(\n\t\thandle,\n\t\t2703428, // IOCTL_BATTERY_QUERY_INFORMATION\n\t\t(*byte)(unsafe.Pointer(&bqi)),\n\t\tuint32(unsafe.Sizeof(bqi)),\n\t\t(*byte)(unsafe.Pointer(&bi)),\n\t\tuint32(unsafe.Sizeof(bi)),\n\t\t&dwOut,\n\t\tnil,\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tb.Full = float64(bi.FullChargedCapacity)\n\n\tbws := batteryWaitStatus{BatteryTag: bqi.BatteryTag}\n\n\tvar bs batteryStatus\n\terr = windows.DeviceIoControl(\n\t\thandle,\n\t\t2703436, // IOCTL_BATTERY_QUERY_STATUS\n\t\t(*byte)(unsafe.Pointer(&bws)),\n\t\tuint32(unsafe.Sizeof(bws)),\n\t\t(*byte)(unsafe.Pointer(&bs)),\n\t\tuint32(unsafe.Sizeof(bs)),\n\t\t&dwOut,\n\t\tnil,\n\t)\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b.Current, err = uint32ToFloat64(bs.Capacity); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif b.Voltage, err = uint32ToFloat64(bs.Voltage); err != nil {\n\t\treturn nil, err\n\t}\n\n\tb.Voltage /= 1000\n\tb.State = readState(bs.PowerState)\n\n\treturn b, nil\n}\n\nfunc systemGetAll() ([]*battery, error) {\n\tvar batteries []*battery\n\tvar i int\n\tvar errs Errors\n\n\tfor i = 0; ; i++ {\n\t\tb, err := systemGet(i)\n\t\tif err == ErrNotFound {\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\terrs = append(errs, err)\n\t\t\tcontinue\n\t\t}\n\t\tbatteries = append(batteries, b)\n\t}\n\n\tif i == 0 {\n\t\treturn nil, &NoBatteryError{}\n\t}\n\n\tif len(batteries) == 0 {\n\t\treturn nil, errs\n\t}\n\n\treturn batteries, nil\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_windows_nix.go",
    "content": "//go:build !darwin && !netbsd && !openbsd && !freebsd\n\npackage battery\n\nimport (\n\t\"math\"\n)\n\n// battery type represents a single battery entry information.\ntype battery struct {\n\t// Current battery state.\n\tState State\n\t// Current (momentary) capacity (in mWh).\n\tCurrent float64\n\t// Last known full capacity (in mWh).\n\tFull float64\n\t// Current voltage (in V).\n\tVoltage float64\n}\n\nfunc mapMostLogicalState(currentState, newState State) State {\n\tswitch currentState {\n\tcase Discharging, NotCharging:\n\t\treturn Discharging\n\tcase Empty:\n\t\treturn newState\n\tcase Charging:\n\t\tif newState == Discharging {\n\t\t\treturn Discharging\n\t\t}\n\t\treturn Charging\n\tcase Unknown:\n\t\treturn newState\n\tcase Full:\n\t\treturn newState\n\t}\n\treturn newState\n}\n\n// Get returns information about all batteries in the system.\n//\n// If error != nil, it will be either ErrFatal or Errors.\n// If error is of type Errors, it is guaranteed that length of both returned slices is the same and that i-th error corresponds with i-th battery structure.\nfunc Get() (*Info, error) {\n\tparseBatteryInfo := func(batteries []*battery) *Info {\n\t\tvar info Info\n\t\tvar current, total float64\n\t\tvar state State\n\t\tfor _, bt := range batteries {\n\t\t\tcurrent += bt.Current\n\t\t\ttotal += bt.Full\n\t\t\tstate = mapMostLogicalState(state, bt.State)\n\t\t}\n\t\tbatteryPercentage := current / total * 100\n\t\tinfo.Percentage = int(math.Min(100, batteryPercentage))\n\t\tinfo.State = state\n\t\treturn &info\n\t}\n\n\tbatteries, err := systemGetAll()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn parseBatteryInfo(batteries), nil\n}\n"
  },
  {
    "path": "src/runtime/battery/battery_windows_nix_test.go",
    "content": "//go:build !darwin && !netbsd && !openbsd\n\n// battery\n// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\nimport (\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestMapBatteriesState(t *testing.T) {\n\tcases := []struct {\n\t\tCase          string\n\t\tExpectedState State\n\t\tCurrentState  State\n\t\tNewState      State\n\t}{\n\t\t{Case: \"charging > charged\", ExpectedState: Charging, CurrentState: Full, NewState: Charging},\n\t\t{Case: \"charging < discharging\", ExpectedState: Discharging, CurrentState: Discharging, NewState: Charging},\n\t\t{Case: \"charging == charging\", ExpectedState: Charging, CurrentState: Charging, NewState: Charging},\n\t\t{Case: \"discharging > charged\", ExpectedState: Discharging, CurrentState: Full, NewState: Discharging},\n\t\t{Case: \"discharging > unknown\", ExpectedState: Discharging, CurrentState: Unknown, NewState: Discharging},\n\t\t{Case: \"discharging > full\", ExpectedState: Discharging, CurrentState: Full, NewState: Discharging},\n\t\t{Case: \"discharging > charging 2\", ExpectedState: Discharging, CurrentState: Charging, NewState: Discharging},\n\t\t{Case: \"discharging > empty\", ExpectedState: Discharging, CurrentState: Empty, NewState: Discharging},\n\t}\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.ExpectedState, mapMostLogicalState(tc.CurrentState, tc.NewState), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/runtime/battery/errors.go",
    "content": "// battery\n// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\nimport \"fmt\"\n\nvar ErrNotFound = fmt.Errorf(\"not found\")\n\ntype Errors []error\n\nfunc (e Errors) Error() string {\n\tvar s string\n\tfor _, err := range e {\n\t\tif err != nil {\n\t\t\ts += err.Error() + \", \"\n\t\t}\n\t}\n\t// strip trailing colon/space\n\tif len(s) > 1 {\n\t\ts = s[:len(s)-2]\n\t}\n\treturn s\n}\n"
  },
  {
    "path": "src/runtime/battery/errors_test.go",
    "content": "// battery\n// Copyright (C) 2016-2017 Karol 'Kenji Takahashi' Woźniak\n//\n// Permission is hereby granted, free of charge, to any person obtaining\n// a copy of this software and associated documentation files (the \"Software\"),\n// to deal in the Software without restriction, including without limitation\n// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n// and/or sell copies of the Software, and to permit persons to whom the\n// Software is furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE\n// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npackage battery\n\nimport (\n\t\"errors\"\n\t\"testing\"\n)\n\nfunc TestErrors(t *testing.T) {\n\tcases := []struct {\n\t\tstr string\n\t\tin  Errors\n\t}{\n\t\t{\"\", Errors{nil}},\n\t\t{\"\", Errors{errors.New(\"\")}},\n\t\t{\"t1\", Errors{errors.New(\"t1\")}},\n\t\t{\"t2, t3\", Errors{errors.New(\"t2\"), errors.New(\"t3\")}},\n\t\t{\"t4, t5\", Errors{errors.New(\"t4\"), errors.New(\"t5\")}},\n\t}\n\n\tfor i, c := range cases {\n\t\tstr := c.in.Error()\n\n\t\tif str != c.str {\n\t\t\tt.Errorf(\"%d: %v != %v\", i, str, c.str)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/runtime/cmd/run.go",
    "content": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"os/exec\"\n\t\"strings\"\n\n\trunjobs \"github.com/jandedobbeleer/oh-my-posh/src/runtime/jobs\"\n)\n\n// Run executes a command while ensuring the OS process is started in its own\n// process group; the started process is recorded so callers can request a\n// cleanup (KillGoroutineChildren) if they decide to abort waiting for the\n// goroutine that spawned it.\nfunc Run(command string, args ...string) (string, error) {\n\tcmd := exec.CommandContext(context.Background(), command, args...)\n\tvar out bytes.Buffer\n\tvar errb bytes.Buffer\n\tcmd.Stdout = &out\n\tcmd.Stderr = &errb\n\n\t// ensure child runs in its own process group so we can kill the tree if\n\t// needed. Implementation is provided by the runtime/jobs package which is\n\t// platform aware.\n\trunjobs.SetProcessGroup(cmd)\n\n\tif err := cmd.Start(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// register the started process under the current goroutine\n\trunjobs.RegisterProcess(cmd.Process.Pid)\n\tdefer runjobs.UnregisterProcess(cmd.Process.Pid)\n\n\tif err := cmd.Wait(); err != nil {\n\t\t// Prefer stderr if available\n\t\toutput := strings.TrimSpace(errb.String())\n\t\tif output == \"\" {\n\t\t\toutput = strings.TrimSpace(out.String())\n\t\t}\n\t\treturn output, err\n\t}\n\n\tresult := strings.TrimSpace(out.String())\n\tif result == \"\" {\n\t\tresult = strings.TrimSpace(errb.String())\n\t}\n\treturn result, nil\n}\n"
  },
  {
    "path": "src/runtime/cmd/run_test.go",
    "content": "package cmd\n\nimport (\n\t\"testing\"\n\n\trunjobs \"github.com/jandedobbeleer/oh-my-posh/src/runtime/jobs\"\n)\n\nfunc TestCurrentGID(t *testing.T) {\n\tif gid := runjobs.CurrentGID(); gid == 0 {\n\t\tt.Fatalf(\"CurrentGID returned 0\")\n\t}\n}\n"
  },
  {
    "path": "src/runtime/environment.go",
    "content": "package runtime\n\nimport (\n\t\"io\"\n\t\"io/fs\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/battery\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\n\tdisk \"github.com/shirou/gopsutil/v4/disk\"\n)\n\nconst (\n\tUNKNOWN = \"unknown\"\n\tWINDOWS = \"windows\"\n\tDARWIN  = \"darwin\"\n\tLINUX   = \"linux\"\n\tFREEBSD = \"freebsd\"\n\tCMD     = \"cmd\"\n\tANDROID = \"android\"\n\n\tPRIMARY = \"primary\"\n)\n\ntype Environment interface {\n\tGetenv(key string) string\n\tPwd() string\n\tHome() string\n\tUser() string\n\tRoot() bool\n\tHost() (string, error)\n\tGOOS() string\n\tShell() string\n\tPlatform() string\n\tStatusCodes() (int, string)\n\tHasFiles(pattern string) bool\n\tHasFilesInDir(dir, pattern string) bool\n\tHasFolder(folder string) bool\n\tHasParentFilePath(input string, followSymlinks bool) (fileInfo *FileInfo, err error)\n\tHasFileInParentDirs(pattern string, depth uint) bool\n\tResolveSymlink(input string) (string, error)\n\tDirMatchesOneOf(dir string, regexes []string) bool\n\tDirIsWritable(input string) bool\n\tCommandPath(command string) string\n\tHasCommand(command string) bool\n\tFileContent(file string) string\n\tLsDir(input string) []fs.DirEntry\n\tRunCommand(command string, args ...string) (string, error)\n\tRunShellCommand(shell, command string) string\n\tExecutionTime() float64\n\tFlags() *Flags\n\tBatteryState() (*battery.Info, error)\n\tQueryWindowTitles(processName, windowTitleRegex string) (string, error)\n\tWindowsRegistryKeyValue(key string) (*WindowsRegistryValue, error)\n\tHTTPRequest(url string, body io.Reader, timeout int, requestModifiers ...http.RequestModifier) ([]byte, error)\n\tIsWsl() bool\n\tIsWsl2() bool\n\tIsCygwin() bool\n\tStackCount() int\n\tTerminalWidth() (int, error)\n\tLogs() string\n\tInWSLSharedDrive() bool\n\tConvertToLinuxPath(input string) string\n\tConvertToWindowsPath(input string) string\n\tConnection(connectionType ConnectionType) (*Connection, error)\n\tCursorPosition() (row, col int)\n\tSystemInfo() (*SystemInfo, error)\n}\n\ntype Flags struct {\n\tType          string\n\tPipeStatus    string\n\tConfigPath    string\n\tPSWD          string\n\tShell         string\n\tShellVersion  string\n\tPWD           string\n\tAbsolutePWD   string\n\tErrorCode     int\n\tPromptCount   int\n\tColumn        int\n\tTerminalWidth int\n\tExecutionTime float64\n\tStackCount    int\n\tConfigHash    uint64\n\tJobCount      int\n\tHasExtra      bool\n\tStrict        bool\n\tDebug         bool\n\tCleared       bool\n\tNoExitCode    bool\n\tInit          bool\n\tMigrate       bool\n\tEval          bool\n\tEscape        bool\n\tIsPrimary     bool\n\tPlain         bool\n\tForce         bool\n\tStreaming     bool\n}\n\ntype CommandError struct {\n\tErr      string\n\tExitCode int\n}\n\nfunc (e *CommandError) Error() string {\n\treturn e.Err\n}\n\ntype FileInfo struct {\n\tParentFolder string\n\tPath         string\n\tIsDir        bool\n}\n\ntype WindowsRegistryValueType string\n\nconst (\n\tDWORD  = \"DWORD\"\n\tQWORD  = \"QWORD\"\n\tBINARY = \"BINARY\"\n\tSTRING = \"STRING\"\n)\n\ntype WindowsRegistryValue struct {\n\tValueType WindowsRegistryValueType\n\tString    string\n\tDWord     uint64\n\tQWord     uint64\n}\n\ntype NotImplemented struct{}\n\nfunc (n *NotImplemented) Error() string {\n\treturn \"not implemented\"\n}\n\ntype ConnectionType string\n\nconst (\n\tETHERNET  ConnectionType = \"ethernet\"\n\tWIFI      ConnectionType = \"wifi\"\n\tCELLULAR  ConnectionType = \"cellular\"\n\tBLUETOOTH ConnectionType = \"bluetooth\"\n)\n\ntype Connection struct {\n\tName         string\n\tType         ConnectionType\n\tSSID         string\n\tTransmitRate uint64\n\tReceiveRate  uint64\n}\n\ntype Memory struct {\n\tPhysicalTotalMemory     uint64\n\tPhysicalAvailableMemory uint64\n\tPhysicalFreeMemory      uint64\n\tPhysicalPercentUsed     float64\n\tSwapTotalMemory         uint64\n\tSwapFreeMemory          uint64\n\tSwapPercentUsed         float64\n}\n\ntype SystemInfo struct {\n\tDisks map[string]disk.IOCountersStat\n\tMemory\n\tLoad1  float64\n\tLoad5  float64\n\tLoad15 float64\n}\n"
  },
  {
    "path": "src/runtime/http/connection.go",
    "content": "//revive:disable:var-naming // package intentionally mirrors standard name for compatibility across runtime\npackage http\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"time\"\n)\n\n// IsConnected checks if we can connect to ohmyposh within 200ms\n// If we can connect, we are connected; otherwise, let's consider being offline\nfunc IsConnected() bool {\n\ttimeout := 200 * time.Millisecond\n\tdialer := &net.Dialer{\n\t\tTimeout: timeout,\n\t}\n\n\tctx := context.Background()\n\tconn, err := dialer.DialContext(ctx, \"tcp\", \"ohmyposh.dev:80\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tconn.Close()\n\treturn true\n}\n"
  },
  {
    "path": "src/runtime/http/download.go",
    "content": "//revive:disable:var-naming // package intentionally mirrors standard name for compatibility across runtime\npackage http\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\thttplib \"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc Download(url string, isCacheEnabled bool) ([]byte, error) {\n\tdefer log.Trace(time.Now(), url)\n\n\t// some users use the blob url, we need to convert it to the raw url\n\tthemeBlob := \"https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/\"\n\turl = strings.Replace(url, themeBlob, \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/\", 1)\n\n\tctx, cncl := context.WithTimeout(context.Background(), time.Second*time.Duration(5))\n\tdefer cncl()\n\n\trequest, err := httplib.NewRequestWithContext(ctx, httplib.MethodGet, url, nil)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\trequest.Header.Add(\"User-Agent\", \"oh-my-posh\")\n\t// if we have an etag, add it to the request to check if the file changed\n\tetag, OK := cache.Get[string](cache.Device, etagKey(url))\n\tif OK {\n\t\tlog.Debugf(\"found etag in cache: %s\", etag)\n\t\trequest.Header.Set(\"If-None-Match\", etag)\n\t}\n\n\tcachedData := func() ([]byte, error) {\n\t\tcachedData, OK := cache.Get[[]byte](cache.Device, dataKey(url))\n\t\tif OK {\n\t\t\treturn cachedData, nil\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"resource not modified but no cached data found\")\n\t}\n\n\tresponse, err := HTTPClient.Do(request)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn cachedData()\n\t}\n\n\tdefer response.Body.Close()\n\n\tif response.StatusCode == httplib.StatusNotModified {\n\t\tlog.Debug(\"resource not modified, using cached version\")\n\t\treturn cachedData()\n\t}\n\n\tif response.StatusCode != httplib.StatusOK {\n\t\terr := fmt.Errorf(\"status code: %d\", response.StatusCode)\n\t\tlog.Error(err)\n\t\treturn cachedData()\n\t}\n\n\tetag = response.Header.Get(\"ETag\")\n\tif etag != \"\" && isCacheEnabled {\n\t\tcache.Set(cache.Device, etagKey(url), etag, cache.INFINITE)\n\t}\n\n\tdata, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn cachedData()\n\t}\n\n\tif isCacheEnabled {\n\t\tcache.Set(cache.Device, dataKey(url), data, cache.INFINITE)\n\t}\n\n\treturn data, nil\n}\n\nfunc etagKey(url string) string {\n\treturn fmt.Sprintf(\"%s.etag\", url)\n}\n\nfunc dataKey(url string) string {\n\treturn fmt.Sprintf(\"%s.data\", url)\n}\n"
  },
  {
    "path": "src/runtime/http/http.go",
    "content": "//revive:disable:var-naming // package intentionally mirrors standard name for compatibility across runtime\npackage http\n\nimport (\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// Inspired by: https://www.thegreatcodeadventure.com/mocking-http-requests-in-golang/\n\ntype httpClient interface {\n\tDo(req *http.Request) (*http.Response, error)\n}\n\nvar (\n\tdefaultTransport http.RoundTripper = &http.Transport{\n\t\tProxy: http.ProxyFromEnvironment,\n\t\tDial: (&net.Dialer{\n\t\t\tTimeout: 10 * time.Second,\n\t\t}).Dial,\n\t\tTLSHandshakeTimeout:   10 * time.Second,\n\t\tResponseHeaderTimeout: 10 * time.Second,\n\t}\n\n\tHTTPClient httpClient = &http.Client{Transport: defaultTransport}\n)\n\ntype Error struct {\n\tStatusCode int\n}\n\nfunc (e *Error) Error() string {\n\treturn http.StatusText(e.StatusCode)\n}\n"
  },
  {
    "path": "src/runtime/http/oauth.go",
    "content": "//revive:disable:var-naming // package intentionally mirrors standard name for compatibility across runtime\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\thttplib \"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n)\n\nconst (\n\tTimeout             = \"timeout\"\n\tInvalidRefreshToken = \"invalid refresh token\"\n\tTokenRefreshFailed  = \"token refresh error\"\n\tDefaultRefreshToken = \"111111111111111111111111111111\"\n)\n\ntype tokenExchange struct {\n\tAccessToken  string `json:\"access_token\"`\n\tRefreshToken string `json:\"refresh_token\"`\n\tExpiresIn    int    `json:\"expires_in\"`\n}\n\ntype OAuthError struct {\n\tmessage string\n}\n\nfunc (a *OAuthError) Error() string {\n\treturn a.message\n}\n\ntype OAuthRequest struct {\n\tAccessTokenKey  string\n\tRefreshTokenKey string\n\tSegmentName     string\n\tRefreshToken    string\n\tAccessToken     string\n\tRequest\n}\n\nfunc (o *OAuthRequest) getAccessToken() (string, error) {\n\t// get directly from cache\n\tif accessToken, OK := cache.Get[string](cache.Device, o.AccessTokenKey); OK && len(accessToken) != 0 {\n\t\treturn accessToken, nil\n\t}\n\n\t// use cached refresh token to get new access token\n\tif refreshToken, OK := cache.Get[string](cache.Device, o.RefreshTokenKey); OK && len(refreshToken) != 0 {\n\t\tif accessToken, err := o.refreshToken(refreshToken); err == nil {\n\t\t\treturn accessToken, nil\n\t\t}\n\t}\n\n\t// use initial refresh token from property\n\t// refreshToken := o.props.GetString(options.RefreshToken, \"\")\n\t// ignore an empty or default refresh token\n\tif o.RefreshToken == \"\" || o.RefreshToken == DefaultRefreshToken {\n\t\treturn \"\", &OAuthError{\n\t\t\tmessage: InvalidRefreshToken,\n\t\t}\n\t}\n\n\t// no need to let the user provide access token, we'll always verify the refresh token\n\taccessToken, err := o.refreshToken(o.RefreshToken)\n\treturn accessToken, err\n}\n\nfunc (o *OAuthRequest) refreshToken(refreshToken string) (string, error) {\n\tif o.HTTPTimeout == 0 {\n\t\to.HTTPTimeout = 20\n\t}\n\n\turl := fmt.Sprintf(\"https://ohmyposh.dev/api/refresh?segment=%s&token=%s\", o.SegmentName, refreshToken)\n\tbody, err := o.Env.HTTPRequest(url, nil, o.HTTPTimeout)\n\tif err != nil {\n\t\treturn \"\", &OAuthError{\n\t\t\t// This might happen if /api was asleep. Assume the user will just retry\n\t\t\tmessage: Timeout,\n\t\t}\n\t}\n\n\ttokens := &tokenExchange{}\n\terr = json.Unmarshal(body, &tokens)\n\tif err != nil {\n\t\treturn \"\", &OAuthError{\n\t\t\tmessage: TokenRefreshFailed,\n\t\t}\n\t}\n\n\t// add tokens to cache\n\tcache.Set(cache.Device, o.AccessTokenKey, tokens.AccessToken, cache.ToDuration(tokens.ExpiresIn))\n\tcache.Set(cache.Device, o.RefreshTokenKey, tokens.RefreshToken, cache.TWOYEARS)\n\treturn tokens.AccessToken, nil\n}\n\nfunc OauthResult[a any](o *OAuthRequest, url string, body io.Reader, requestModifiers ...RequestModifier) (a, error) {\n\taccessToken, err := o.getAccessToken()\n\tif err != nil {\n\t\tvar data a\n\t\treturn data, err\n\t}\n\n\t// add token to header for authentication\n\taddAuthHeader := func(request *httplib.Request) {\n\t\trequest.Header.Add(\"Authorization\", \"Bearer \"+accessToken)\n\t}\n\n\tif requestModifiers == nil {\n\t\trequestModifiers = []RequestModifier{}\n\t}\n\n\trequestModifiers = append(requestModifiers, addAuthHeader)\n\n\treturn Do[a](&o.Request, url, body, requestModifiers...)\n}\n"
  },
  {
    "path": "src/runtime/http/oauth_test.go",
    "content": "//revive:disable:var-naming // test package matches implementation; lint warning is intentional\npackage http\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype data struct {\n\tHello string `json:\"hello\"`\n}\n\nfunc TestOauthResult(t *testing.T) {\n\taccessTokenKey := \"test_access_token\"\n\trefreshTokenKey := \"test_refresh_token\"\n\ttokenResponse := `{ \"access_token\":\"NEW_ACCESSTOKEN\",\"refresh_token\":\"NEW_REFRESHTOKEN\", \"expires_in\":1234 }`\n\tjsonResponse := `{ \"hello\":\"world\" }`\n\tsuccessData := &data{Hello: \"world\"}\n\n\tcases := []struct {\n\t\tError                 error\n\t\tExpectedData          *data\n\t\tAccessToken           string\n\t\tRefreshToken          string\n\t\tTokenResponse         string\n\t\tJSONResponse          string\n\t\tCacheJSONResponse     string\n\t\tCase                  string\n\t\tExpectedErrorMessage  string\n\t\tCacheTimeout          int\n\t\tResponseCacheMiss     bool\n\t\tAccessTokenFromCache  bool\n\t\tRefreshTokenFromCache bool\n\t}{\n\t\t{\n\t\t\tCase:                 \"No initial tokens\",\n\t\t\tExpectedErrorMessage: InvalidRefreshToken,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Use config tokens\",\n\t\t\tAccessToken:   \"INITIAL_ACCESSTOKEN\",\n\t\t\tRefreshToken:  \"INITIAL_REFRESHTOKEN\",\n\t\t\tTokenResponse: tokenResponse,\n\t\t\tJSONResponse:  jsonResponse,\n\t\t\tExpectedData:  successData,\n\t\t},\n\t\t{\n\t\t\tCase:                 \"Access token from cache\",\n\t\t\tAccessToken:          \"ACCESSTOKEN\",\n\t\t\tAccessTokenFromCache: true,\n\t\t\tJSONResponse:         jsonResponse,\n\t\t\tExpectedData:         successData,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Refresh token from cache\",\n\t\t\tRefreshToken:          \"REFRESH_TOKEN\",\n\t\t\tRefreshTokenFromCache: true,\n\t\t\tJSONResponse:          jsonResponse,\n\t\t\tTokenResponse:         tokenResponse,\n\t\t\tExpectedData:          successData,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Refresh token from cache, success\",\n\t\t\tRefreshToken:          \"REFRESH_TOKEN\",\n\t\t\tRefreshTokenFromCache: true,\n\t\t\tJSONResponse:          jsonResponse,\n\t\t\tTokenResponse:         tokenResponse,\n\t\t\tExpectedData:          successData,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Refresh API error\",\n\t\t\tRefreshToken:          \"REFRESH_TOKEN\",\n\t\t\tRefreshTokenFromCache: true,\n\t\t\tError:                 fmt.Errorf(\"API error\"),\n\t\t\tExpectedErrorMessage:  Timeout,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Refresh API parse error\",\n\t\t\tRefreshToken:          \"REFRESH_TOKEN\",\n\t\t\tRefreshTokenFromCache: true,\n\t\t\tTokenResponse:         \"INVALID_JSON\",\n\t\t\tExpectedErrorMessage:  TokenRefreshFailed,\n\t\t},\n\t\t{\n\t\t\tCase:                 \"Default config token\",\n\t\t\tRefreshToken:         DefaultRefreshToken,\n\t\t\tExpectedErrorMessage: InvalidRefreshToken,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Cache data, invalid data\",\n\t\t\tRefreshToken:  \"REFRESH_TOKEN\",\n\t\t\tTokenResponse: tokenResponse,\n\t\t\tJSONResponse:  jsonResponse,\n\t\t\tExpectedData:  successData,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Cache data, no cache\",\n\t\t\tRefreshToken:  \"REFRESH_TOKEN\",\n\t\t\tTokenResponse: tokenResponse,\n\t\t\tJSONResponse:  jsonResponse,\n\t\t\tExpectedData:  successData,\n\t\t},\n\t\t{\n\t\t\tCase:                 \"API body failure\",\n\t\t\tAccessToken:          \"ACCESSTOKEN\",\n\t\t\tAccessTokenFromCache: true,\n\t\t\tJSONResponse:         \"ERR\",\n\t\t\tExpectedErrorMessage: \"invalid character 'E' looking for beginning of value\",\n\t\t},\n\t\t{\n\t\t\tCase:                 \"API request failure\",\n\t\t\tAccessToken:          \"ACCESSTOKEN\",\n\t\t\tAccessTokenFromCache: true,\n\t\t\tJSONResponse:         \"ERR\",\n\t\t\tError:                fmt.Errorf(\"no response\"),\n\t\t\tExpectedErrorMessage: \"no response\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\turl := \"https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1\"\n\t\ttokenURL := fmt.Sprintf(\"https://ohmyposh.dev/api/refresh?segment=test&token=%s\", tc.RefreshToken)\n\n\t\tif tc.AccessTokenFromCache {\n\t\t\tcache.Set(cache.Device, accessTokenKey, tc.AccessToken, cache.INFINITE)\n\t\t}\n\n\t\tif tc.RefreshTokenFromCache {\n\t\t\tcache.Set(cache.Device, refreshTokenKey, tc.RefreshToken, cache.INFINITE)\n\t\t}\n\n\t\tenv := &MockedEnvironment{}\n\n\t\tenv.On(\"HTTPRequest\", url).Return([]byte(tc.JSONResponse), tc.Error)\n\t\tenv.On(\"HTTPRequest\", tokenURL).Return([]byte(tc.TokenResponse), tc.Error)\n\n\t\toauth := &OAuthRequest{\n\t\t\tAccessTokenKey:  accessTokenKey,\n\t\t\tRefreshTokenKey: refreshTokenKey,\n\t\t\tSegmentName:     \"test\",\n\t\t\tAccessToken:     tc.AccessToken,\n\t\t\tRefreshToken:    tc.RefreshToken,\n\t\t\tRequest: Request{\n\t\t\t\tEnv:         env,\n\t\t\t\tHTTPTimeout: 20,\n\t\t\t},\n\t\t}\n\n\t\tgot, err := OauthResult[*data](oauth, url, nil)\n\t\tassert.Equal(t, tc.ExpectedData, got, tc.Case)\n\n\t\tif tc.ExpectedErrorMessage == \"\" {\n\t\t\tassert.Nil(t, err, tc.Case)\n\t\t} else {\n\t\t\tassert.Equal(t, tc.ExpectedErrorMessage, err.Error(), tc.Case)\n\t\t}\n\n\t\tcache.DeleteAll(cache.Device)\n\t}\n}\n"
  },
  {
    "path": "src/runtime/http/request.go",
    "content": "//revive:disable:var-naming // package intentionally mirrors standard name for compatibility across runtime\npackage http\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype RequestModifier func(request *http.Request)\n\ntype Request struct {\n\tEnv         Environment\n\tHTTPTimeout int\n}\n\ntype Environment interface {\n\tHTTPRequest(url string, body io.Reader, timeout int, requestModifiers ...RequestModifier) ([]byte, error)\n}\n\nfunc Do[a any](r *Request, url string, body io.Reader, requestModifiers ...RequestModifier) (a, error) {\n\tvar data a\n\thttpTimeout := r.HTTPTimeout // r.props.GetInt(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tresponseBody, err := r.Env.HTTPRequest(url, body, httpTimeout, requestModifiers...)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn data, err\n\t}\n\n\terr = json.Unmarshal(responseBody, &data)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn data, err\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "src/runtime/http/request_test.go",
    "content": "//revive:disable:var-naming // test package matches implementation; lint warning is intentional\npackage http\n\nimport (\n\t\"io\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\ntype MockedEnvironment struct {\n\ttestify_.Mock\n}\n\nfunc (env *MockedEnvironment) HTTPRequest(url string, _ io.Reader, _ int, _ ...RequestModifier) ([]byte, error) {\n\targs := env.Called(url)\n\treturn args.Get(0).([]byte), args.Error(1)\n}\n\nfunc TestRequestResult(t *testing.T) {\n\tsuccessData := &data{Hello: \"world\"}\n\tjsonResponse := `{ \"hello\":\"world\" }`\n\turl := \"https://google.com?q=hello\"\n\n\tcases := []struct {\n\t\tError                error\n\t\tExpectedData         *data\n\t\tCase                 string\n\t\tJSONResponse         string\n\t\tCacheJSONResponse    string\n\t\tExpectedErrorMessage string\n\t\tCacheTimeout         int\n\t\tResponseCacheMiss    bool\n\t}{\n\t\t{\n\t\t\tCase:         \"No cache\",\n\t\t\tJSONResponse: jsonResponse,\n\t\t\tExpectedData: successData,\n\t\t},\n\t\t{\n\t\t\tCase:                 \"DNS error\",\n\t\t\tError:                &net.DNSError{IsNotFound: true},\n\t\t\tExpectedErrorMessage: \"lookup : \",\n\t\t},\n\t\t{\n\t\t\tCase:                 \"Response incorrect\",\n\t\t\tJSONResponse:         `[`,\n\t\t\tExpectedErrorMessage: \"unexpected end of JSON input\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &MockedEnvironment{}\n\t\tenv.On(\"HTTPRequest\", url).Return([]byte(tc.JSONResponse), tc.Error)\n\n\t\trequest := &Request{\n\t\t\tEnv:         env,\n\t\t\tHTTPTimeout: 0,\n\t\t}\n\n\t\tgot, err := Do[*data](request, url, nil)\n\t\tassert.Equal(t, tc.ExpectedData, got, tc.Case)\n\t\tif tc.ExpectedErrorMessage == \"\" {\n\t\t\tassert.Nil(t, err, tc.Case)\n\t\t} else {\n\t\t\tassert.Equal(t, tc.ExpectedErrorMessage, err.Error(), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/runtime/jobs/jobs_common.go",
    "content": "package jobs\n\nimport (\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// CurrentGID returns the current goroutine's id. We expose this here so\n// callers can register PIDs without parsing runtime.Stack in multiple\n// places.\nfunc CurrentGID() uint64 {\n\tbuf := make([]byte, 64)\n\tn := runtime.Stack(buf, false)\n\ts := strings.Fields(strings.TrimPrefix(string(buf[:n]), \"goroutine \"))\n\tif len(s) == 0 {\n\t\treturn 0\n\t}\n\tidStr := s[0]\n\tid, err := strconv.ParseUint(idStr, 10, 64)\n\tif err != nil {\n\t\treturn 0\n\t}\n\treturn id\n}\n"
  },
  {
    "path": "src/runtime/jobs/jobs_other.go",
    "content": "//go:build !windows\n\npackage jobs\n\nimport (\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n)\n\nvar (\n\tprocessesMu sync.Mutex\n\tprocesses   = map[uint64]map[int]struct{}{}\n)\n\nfunc CreateJobForGoroutine(_ string) error { return nil }\nfunc AssignPidToGoroutineJob(_ int) error  { return nil }\n\n// setProcessGroup ensures the child process runs in its own process group so\n// it can be killed with a group kill (negative pid).\nfunc SetProcessGroup(cmd *exec.Cmd) {\n\tcmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}\n}\n\n// registerProcessWithGID keeps track of a started child process for the\n// given goroutine id.\nfunc RegisterProcess(pid int) {\n\tgid := CurrentGID()\n\tprocessesMu.Lock()\n\tm := processes[gid]\n\tif m == nil {\n\t\tm = map[int]struct{}{}\n\t\tprocesses[gid] = m\n\t}\n\tm[pid] = struct{}{}\n\tprocessesMu.Unlock()\n}\n\nfunc UnregisterProcess(pid int) {\n\tgid := CurrentGID()\n\tprocessesMu.Lock()\n\tif m, ok := processes[gid]; ok {\n\t\tdelete(m, pid)\n\t\tif len(m) == 0 {\n\t\t\tdelete(processes, gid)\n\t\t}\n\t}\n\tprocessesMu.Unlock()\n}\n\n// KillGoroutineChildren attempts to kill all child processes started by the\n// goroutine identified by gid using process groups (PGID). This mirrors the\n// previous behavior performed in runtime/cmd.\nfunc KillGoroutineChildren(gid uint64) error {\n\tprocessesMu.Lock()\n\tpidsMap, ok := processes[gid]\n\tif !ok || len(pidsMap) == 0 {\n\t\tprocessesMu.Unlock()\n\t\treturn nil\n\t}\n\tpids := make([]int, 0, len(pidsMap))\n\tfor pid := range pidsMap {\n\t\tpids = append(pids, pid)\n\t}\n\tdelete(processes, gid)\n\tprocessesMu.Unlock()\n\n\tvar errs []string\n\tfor _, pid := range pids {\n\t\t// negative pid kills the process group\n\t\tif err := syscall.Kill(-pid, syscall.SIGKILL); err != nil {\n\t\t\terrs = append(errs, fmt.Sprintf(\"kill -%d: %v\", pid, err))\n\t\t}\n\t}\n\n\tif len(errs) > 0 {\n\t\treturn fmt.Errorf(\"failed to kill child processes: %s\", strings.Join(errs, \"; \"))\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "src/runtime/jobs/jobs_windows.go",
    "content": "//go:build windows\n\npackage jobs\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\tjobsMu      sync.Mutex\n\tjobs        = map[uint64]windows.Handle{}\n\tprocessesMu sync.Mutex\n\tprocesses   = map[uint64]map[int]struct{}{}\n)\n\n// CreateJobForGoroutine creates a Job object for gid and sets the\n// JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag so closing/terminating the job\n// kills all assigned processes.\nfunc CreateJobForGoroutine(label string) error {\n\tgid := CurrentGID()\n\tdefer log.Trace(time.Now(), fmt.Sprintf(\"creating job for goroutine(%s): %d\", label, gid))\n\n\tjobsMu.Lock()\n\tif _, ok := jobs[gid]; ok {\n\t\tjobsMu.Unlock()\n\t\treturn nil\n\t}\n\tjobsMu.Unlock()\n\n\tjob, err := windows.CreateJobObject(nil, nil)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION\n\tinfo.BasicLimitInformation.LimitFlags = windows.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE\n\n\tsize := uint32(unsafe.Sizeof(info))\n\tif _, err := windows.SetInformationJobObject(job, windows.JobObjectExtendedLimitInformation, uintptr(unsafe.Pointer(&info)), size); err != nil {\n\t\t_ = windows.CloseHandle(job)\n\t}\n\n\tjobsMu.Lock()\n\tjobs[gid] = job\n\tjobsMu.Unlock()\n\n\treturn nil\n}\n\n// registerProcessWithGID keeps track of a started child process for the\n// given goroutine id and attempts to assign it to the Job object if present.\nfunc RegisterProcess(pid int) {\n\tgid := CurrentGID()\n\tprocessesMu.Lock()\n\tm := processes[gid]\n\tif m == nil {\n\t\tm = map[int]struct{}{}\n\t\tprocesses[gid] = m\n\t}\n\n\tm[pid] = struct{}{}\n\tprocessesMu.Unlock()\n\n\t// Try to assign to job if exists (best-effort)\n\tjobsMu.Lock()\n\tjob, ok := jobs[gid]\n\tjobsMu.Unlock()\n\tif !ok {\n\t\tlog.Debugf(\"no job found for goroutine %d when assigning pid %d\", gid, pid)\n\t\treturn\n\t}\n\n\tproc, err := windows.OpenProcess(windows.PROCESS_SET_QUOTA|windows.PROCESS_TERMINATE, false, uint32(pid))\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tdefer func() {\n\t\terr = windows.CloseHandle(proc)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t}()\n\n\tif err = windows.AssignProcessToJobObject(job, proc); err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tlog.Debugf(\"successfully added process to job for goroutine: %d, pid: %d\", gid, pid)\n}\n\nfunc UnregisterProcess(pid int) {\n\tgid := CurrentGID()\n\tprocessesMu.Lock()\n\n\tif m, ok := processes[gid]; ok {\n\t\tdelete(m, pid)\n\t\tif len(m) == 0 {\n\t\t\tdelete(processes, gid)\n\t\t}\n\t}\n\n\tprocessesMu.Unlock()\n}\n\n// KillGoroutineChildren will first try to terminate a Job if present, and\n// otherwise will fall back to taskkill for each recorded pid.\nfunc KillGoroutineChildren(gid uint64) error {\n\t// if Job exists, prefer terminating the Job\n\tjobsMu.Lock()\n\tjob, hasJob := jobs[gid]\n\tif hasJob {\n\t\tdelete(jobs, gid)\n\t}\n\tjobsMu.Unlock()\n\tif hasJob {\n\t\t// Terminate the job which kills all processes in it\n\t\tif err := windows.TerminateJobObject(job, 1); err == nil {\n\t\t\t// cleanup recorded pids as well\n\t\t\tprocessesMu.Lock()\n\t\t\tdelete(processes, gid)\n\t\t\tprocessesMu.Unlock()\n\t\t\tlog.Debugf(\"successfully terminated job object for goroutine: %d\", gid)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// No job or terminate failed; fall back to per-pid taskkill\n\tprocessesMu.Lock()\n\tpidsMap, ok := processes[gid]\n\tif !ok || len(pidsMap) == 0 {\n\t\tprocessesMu.Unlock()\n\t\treturn nil\n\t}\n\tpids := make([]int, 0, len(pidsMap))\n\tfor pid := range pidsMap {\n\t\tpids = append(pids, pid)\n\t}\n\tdelete(processes, gid)\n\tprocessesMu.Unlock()\n\n\tvar errs []string\n\tfor _, pid := range pids {\n\t\tif err := exec.CommandContext(context.Background(), \"taskkill\", \"/T\", \"/F\", \"/PID\", strconv.Itoa(pid)).Run(); err != nil {\n\t\t\terrs = append(errs, fmt.Sprintf(\"taskkill %d: %v\", pid, err))\n\t\t}\n\t}\n\n\tif len(errs) > 0 {\n\t\treturn fmt.Errorf(\"failed to kill child processes: %s\", strings.Join(errs, \"; \"))\n\t}\n\treturn nil\n}\n\n// setProcessGroup ensures the child process runs in its own process group\n// (CREATE_NEW_PROCESS_GROUP) so it can be terminated as a group.\nfunc SetProcessGroup(cmd *exec.Cmd) {\n\tcmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP}\n}\n"
  },
  {
    "path": "src/runtime/mock/environment.go",
    "content": "package mock\n\nimport (\n\t\"io\"\n\t\"io/fs\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/battery\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\n\tmock \"github.com/stretchr/testify/mock\"\n)\n\ntype Environment struct {\n\tmock.Mock\n}\n\nfunc (env *Environment) Getenv(key string) string {\n\targs := env.Called(key)\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Pwd() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Home() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) HasFiles(pattern string) bool {\n\targs := env.Called(pattern)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) HasFilesInDir(dir, pattern string) bool {\n\targs := env.Called(dir, pattern)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) HasFolder(folder string) bool {\n\targs := env.Called(folder)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) ResolveSymlink(input string) (string, error) {\n\targs := env.Called(input)\n\treturn args.String(0), args.Error(1)\n}\n\nfunc (env *Environment) FileContent(file string) string {\n\targs := env.Called(file)\n\treturn args.String(0)\n}\n\nfunc (env *Environment) LsDir(input string) []fs.DirEntry {\n\targs := env.Called(input)\n\treturn args.Get(0).([]fs.DirEntry)\n}\n\nfunc (env *Environment) User() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Host() (string, error) {\n\targs := env.Called()\n\treturn args.String(0), args.Error(1)\n}\n\nfunc (env *Environment) GOOS() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Platform() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) CommandPath(command string) string {\n\targs := env.Called(command)\n\treturn args.String(0)\n}\n\nfunc (env *Environment) HasCommand(command string) bool {\n\targs := env.Called(command)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) RunCommand(command string, args ...string) (string, error) {\n\targuments := env.Called(command, args)\n\treturn arguments.String(0), arguments.Error(1)\n}\n\nfunc (env *Environment) RunShellCommand(shell, command string) string {\n\targs := env.Called(shell, command)\n\treturn args.String(0)\n}\n\nfunc (env *Environment) StatusCodes() (int, string) {\n\targs := env.Called()\n\treturn args.Int(0), args.String(1)\n}\n\nfunc (env *Environment) ExecutionTime() float64 {\n\targs := env.Called()\n\treturn float64(args.Int(0))\n}\n\nfunc (env *Environment) Root() bool {\n\targs := env.Called()\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) Flags() *runtime.Flags {\n\targuments := env.Called()\n\treturn arguments.Get(0).(*runtime.Flags)\n}\n\nfunc (env *Environment) BatteryState() (*battery.Info, error) {\n\targs := env.Called()\n\treturn args.Get(0).(*battery.Info), args.Error(1)\n}\n\nfunc (env *Environment) Shell() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) QueryWindowTitles(processName, windowTitleRegex string) (string, error) {\n\targs := env.Called(processName, windowTitleRegex)\n\treturn args.String(0), args.Error(1)\n}\n\nfunc (env *Environment) WindowsRegistryKeyValue(path string) (*runtime.WindowsRegistryValue, error) {\n\targs := env.Called(path)\n\treturn args.Get(0).(*runtime.WindowsRegistryValue), args.Error(1)\n}\n\nfunc (env *Environment) HTTPRequest(url string, _ io.Reader, _ int, _ ...http.RequestModifier) ([]byte, error) {\n\targs := env.Called(url)\n\treturn args.Get(0).([]byte), args.Error(1)\n}\n\nfunc (env *Environment) HasParentFilePath(parent string, followSymlinks bool) (*runtime.FileInfo, error) {\n\targs := env.Called(parent, followSymlinks)\n\treturn args.Get(0).(*runtime.FileInfo), args.Error(1)\n}\n\nfunc (env *Environment) StackCount() int {\n\targs := env.Called()\n\treturn args.Int(0)\n}\n\nfunc (env *Environment) IsWsl() bool {\n\targs := env.Called()\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) IsWsl2() bool {\n\targs := env.Called()\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) IsCygwin() bool {\n\targs := env.Called()\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) TerminalWidth() (int, error) {\n\targs := env.Called()\n\treturn args.Int(0), args.Error(1)\n}\n\nfunc (env *Environment) CachePath() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Close() {\n\t_ = env.Called()\n}\n\nfunc (env *Environment) Logs() string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) InWSLSharedDrive() bool {\n\targs := env.Called()\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) ConvertToWindowsPath(input string) string {\n\targs := env.Called(input)\n\treturn args.String(0)\n}\n\nfunc (env *Environment) ConvertToLinuxPath(_ string) string {\n\targs := env.Called()\n\treturn args.String(0)\n}\n\nfunc (env *Environment) Connection(connectionType runtime.ConnectionType) (*runtime.Connection, error) {\n\targs := env.Called(connectionType)\n\treturn args.Get(0).(*runtime.Connection), args.Error(1)\n}\n\nfunc (env *Environment) MockGitCommand(dir, returnValue string, args ...string) {\n\targs = append([]string{\"-C\", dir, \"--no-optional-locks\", \"-c\", \"core.quotepath=false\", \"-c\", \"color.status=false\"}, args...)\n\tenv.On(\"RunCommand\", \"git\", args).Return(returnValue, nil)\n}\n\nfunc (env *Environment) MockHgCommand(dir, returnValue string, args ...string) {\n\targs = append([]string{\"-R\", dir}, args...)\n\tenv.On(\"RunCommand\", \"hg\", args).Return(returnValue, nil)\n}\n\nfunc (env *Environment) MockJjCommand(dir, returnValue string, args ...string) {\n\targs = append([]string{\"--repository\", dir, \"--no-pager\", \"--color\", \"never\", \"--ignore-working-copy\"}, args...)\n\tenv.On(\"RunCommand\", \"jj\", args).Return(returnValue, nil)\n}\n\nfunc (env *Environment) MockSvnCommand(dir, returnValue string, args ...string) {\n\targs = append([]string{\"-C\", dir, \"--no-optional-locks\", \"-c\", \"core.quotepath=false\", \"-c\", \"color.status=false\"}, args...)\n\tenv.On(\"RunCommand\", \"svn\", args).Return(returnValue, nil)\n}\n\nfunc (env *Environment) HasFileInParentDirs(pattern string, depth uint) bool {\n\targs := env.Called(pattern, depth)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) DirMatchesOneOf(dir string, regexes []string) bool {\n\targs := env.Called(dir, regexes)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) DirIsWritable(path string) bool {\n\targs := env.Called(path)\n\treturn args.Bool(0)\n}\n\nfunc (env *Environment) CursorPosition() (int, int) {\n\targs := env.Called()\n\treturn args.Int(0), args.Int(1)\n}\n\nfunc (env *Environment) SystemInfo() (*runtime.SystemInfo, error) {\n\targs := env.Called()\n\treturn args.Get(0).(*runtime.SystemInfo), args.Error(1)\n}\n\nfunc (env *Environment) Unset(name string) {\n\tfor i := 0; i < len(env.ExpectedCalls); i++ {\n\t\tf := env.ExpectedCalls[i]\n\t\tif f.Method == name {\n\t\t\tf.Unset()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/runtime/networks_windows.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\twlanapi             = syscall.NewLazyDLL(\"wlanapi.dll\")\n\thWlanOpenHandle     = wlanapi.NewProc(\"WlanOpenHandle\")\n\thWlanCloseHandle    = wlanapi.NewProc(\"WlanCloseHandle\")\n\thWlanQueryInterface = wlanapi.NewProc(\"WlanQueryInterface\")\n\thWlanEnumInterfaces = wlanapi.NewProc(\"WlanEnumInterfaces\")\n)\n\ntype MIN_IF_TABLE2 struct {\n\tNumEntries uint64\n\tTable      [256]MIB_IF_ROW2\n}\n\nconst (\n\tIF_MAX_STRING_SIZE         uint64 = 256\n\tIF_MAX_PHYS_ADDRESS_LENGTH uint64 = 32\n)\n\ntype MIB_IF_ROW2 struct {\n\tInterfaceLuid            uint64\n\tInterfaceIndex           uint32\n\tInterfaceGUID            windows.GUID\n\tAlias                    [IF_MAX_STRING_SIZE + 1]uint16\n\tDescription              [IF_MAX_STRING_SIZE + 1]uint16\n\tPhysicalAddressLength    uint32\n\tPhysicalAddress          [IF_MAX_PHYS_ADDRESS_LENGTH]uint8\n\tPermanentPhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8\n\n\tMtu                uint32\n\tType               uint32\n\tTunnelType         uint32\n\tMediaType          uint32\n\tPhysicalMediumType uint32\n\tAccessType         uint32\n\tDirectionType      uint32\n\n\tInterfaceAndOperStatusFlags struct {\n\t\tHardwareInterface bool\n\t\tFilterInterface   bool\n\t\tConnectorPresent  bool\n\t\tNotAuthenticated  bool\n\t\tNotMediaConnected bool\n\t\tPaused            bool\n\t\tLowPower          bool\n\t\tEndPointInterface bool\n\t}\n\n\tOperStatus        uint32\n\tAdminStatus       uint32\n\tMediaConnectState uint32\n\tNetworkGUID       windows.GUID\n\tConnectionType    uint32\n\n\tTransmitLinkSpeed uint64\n\tReceiveLinkSpeed  uint64\n\n\tInOctets           uint64\n\tInUcastPkts        uint64\n\tInNUcastPkts       uint64\n\tInDiscards         uint64\n\tInErrors           uint64\n\tInUnknownProtos    uint64\n\tInUcastOctets      uint64\n\tInMulticastOctets  uint64\n\tInBroadcastOctets  uint64\n\tOutOctets          uint64\n\tOutUcastPkts       uint64\n\tOutNUcastPkts      uint64\n\tOutDiscards        uint64\n\tOutErrors          uint64\n\tOutUcastOctets     uint64\n\tOutMulticastOctets uint64\n\tOutBroadcastOctets uint64\n\tOutQLen            uint64\n}\n\n//nolint:unused\ntype WLAN_INTERFACE_INFO_LIST struct {\n\tdwNumberOfItems uint32\n\tdwIndex         uint32\n\tInterfaceInfo   [1]WLAN_INTERFACE_INFO\n}\n\ntype WLAN_INTERFACE_INFO struct {\n\tInterfaceGuid           syscall.GUID\n\tstrInterfaceDescription [256]uint16\n\tisState                 uint32\n}\n\nconst (\n\tWLAN_MAX_NAME_LENGTH  int64 = 256\n\tDOT11_SSID_MAX_LENGTH int64 = 32\n)\n\n//nolint:unused\ntype WLAN_CONNECTION_ATTRIBUTES struct {\n\tisState                   uint32\n\twlanConnectionMode        uint32\n\tstrProfileName            [WLAN_MAX_NAME_LENGTH]uint16\n\twlanAssociationAttributes WLAN_ASSOCIATION_ATTRIBUTES\n\twlanSecurityAttributes    WLAN_SECURITY_ATTRIBUTES\n}\n\n//nolint:unused\ntype WLAN_ASSOCIATION_ATTRIBUTES struct {\n\tdot11Ssid         DOT11_SSID\n\tdot11BssType      uint32\n\tdot11Bssid        [6]uint8\n\tdot11PhyType      uint32\n\tuDot11PhyIndex    uint32\n\twlanSignalQuality uint32\n\tulRxRate          uint32\n\tulTxRate          uint32\n}\n\n//nolint:unused\ntype WLAN_SECURITY_ATTRIBUTES struct {\n\tbSecurityEnabled     uint32\n\tbOneXEnabled         uint32\n\tdot11AuthAlgorithm   uint32\n\tdot11CipherAlgorithm uint32\n}\n\ntype DOT11_SSID struct {\n\tuSSIDLength uint32\n\tucSSID      [DOT11_SSID_MAX_LENGTH]uint8\n}\n\nfunc (term *Terminal) getConnections() []*Connection {\n\tvar pIFTable2 *MIN_IF_TABLE2\n\t_, _, _ = hGetIfTable2.Call(uintptr(unsafe.Pointer(&pIFTable2)))\n\n\tnetworks := make([]*Connection, 0)\n\n\tfor i := 0; i < int(pIFTable2.NumEntries); i++ {\n\t\tnetworkInterface := pIFTable2.Table[i]\n\t\talias := strings.TrimRight(syscall.UTF16ToString(networkInterface.Alias[:]), \"\\x00\")\n\n\t\tif networkInterface.OperStatus != 1 || // not connected or functional\n\t\t\t!networkInterface.InterfaceAndOperStatusFlags.HardwareInterface || // rule out software interfaces\n\t\t\tstrings.HasPrefix(alias, \"Local Area Connection\") || // not relevant\n\t\t\tstrings.Index(alias, \"-\") >= 3 { // rule out parts of Ethernet filter interfaces\n\t\t\t// e.g. : \"Ethernet-WFP Native MAC Layer LightWeight Filter-0000\"\n\t\t\tcontinue\n\t\t}\n\n\t\tvar connectionType ConnectionType\n\t\tvar ssid string\n\t\tswitch networkInterface.Type {\n\t\tcase 6:\n\t\t\tconnectionType = ETHERNET\n\t\tcase 237, 234, 244:\n\t\t\tconnectionType = CELLULAR\n\t\t}\n\n\t\tif networkInterface.PhysicalMediumType == 10 {\n\t\t\tconnectionType = BLUETOOTH\n\t\t}\n\n\t\t// skip connections which aren't relevant\n\t\tif connectionType == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Debugf(\"Found network interface: %s\", alias)\n\n\t\tnetwork := &Connection{\n\t\t\tType:         connectionType,\n\t\t\tName:         alias,\n\t\t\tTransmitRate: networkInterface.TransmitLinkSpeed,\n\t\t\tReceiveRate:  networkInterface.ReceiveLinkSpeed,\n\t\t\tSSID:         ssid,\n\t\t}\n\n\t\tnetworks = append(networks, network)\n\t}\n\n\twifi, err := term.wifiNetwork()\n\tif err == nil {\n\t\tnetworks = append(networks, wifi)\n\t\treturn networks\n\t}\n\n\tlog.Error(err)\n\n\treturn networks\n}\n\nfunc (term *Terminal) wifiNetwork() (*Connection, error) {\n\tdefer log.Trace(time.Now())\n\t// Open handle\n\tvar pdwNegotiatedVersion uint32\n\tvar phClientHandle uint32\n\te, _, err := hWlanOpenHandle.Call(uintptr(uint32(2)), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&pdwNegotiatedVersion)), uintptr(unsafe.Pointer(&phClientHandle)))\n\tif e != 0 {\n\t\treturn nil, err\n\t}\n\n\tdefer func() {\n\t\t_, _, _ = hWlanCloseHandle.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)))\n\t}()\n\n\t// list interfaces\n\tvar interfaceList *WLAN_INTERFACE_INFO_LIST\n\te, _, err = hWlanEnumInterfaces.Call(uintptr(phClientHandle), uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(&interfaceList)))\n\tif e != 0 {\n\t\treturn nil, err\n\t}\n\n\t// use first interface that is connected\n\tnumberOfInterfaces := int(interfaceList.dwNumberOfItems)\n\tinfoSize := unsafe.Sizeof(interfaceList.InterfaceInfo[0])\n\tfor i := range numberOfInterfaces {\n\t\tnetwork := (*WLAN_INTERFACE_INFO)(unsafe.Add(unsafe.Pointer(&interfaceList.InterfaceInfo[0]), uintptr(i)*infoSize))\n\t\tif network.isState != 1 {\n\t\t\tlog.Debug(\"Skipping non-connected wifi interface\")\n\t\t\tcontinue\n\t\t}\n\n\t\treturn term.parseNetworkInterface(network, phClientHandle)\n\t}\n\n\treturn nil, errors.New(\"not connected\")\n}\n\nfunc (term *Terminal) parseNetworkInterface(network *WLAN_INTERFACE_INFO, clientHandle uint32) (*Connection, error) {\n\tinfo := Connection{\n\t\tType: WIFI,\n\t}\n\n\t// Query wifi connection state\n\tvar dataSize uint32\n\tvar wlanAttr *WLAN_CONNECTION_ATTRIBUTES\n\te, _, err := hWlanQueryInterface.Call(uintptr(clientHandle),\n\t\tuintptr(unsafe.Pointer(&network.InterfaceGuid)),\n\t\tuintptr(7), // wlan_intf_opcode_current_connection\n\t\tuintptr(unsafe.Pointer(nil)),\n\t\tuintptr(unsafe.Pointer(&dataSize)),\n\t\tuintptr(unsafe.Pointer(&wlanAttr)),\n\t\tuintptr(unsafe.Pointer(nil)))\n\tif e != 0 {\n\t\treturn &info, err\n\t}\n\n\t// SSID\n\tssid := wlanAttr.wlanAssociationAttributes.dot11Ssid\n\tif ssid.uSSIDLength > 0 {\n\t\tinfo.SSID = string(ssid.ucSSID[0:ssid.uSSIDLength])\n\t\tinfo.Name = info.SSID\n\t\tlog.Debugf(\"Found wifi interface: %s\", info.SSID)\n\t}\n\n\tinfo.TransmitRate = uint64(wlanAttr.wlanAssociationAttributes.ulTxRate / 1024)\n\tinfo.ReceiveRate = uint64(wlanAttr.wlanAssociationAttributes.ulRxRate / 1024)\n\n\treturn &info, nil\n}\n"
  },
  {
    "path": "src/runtime/path/clean.go",
    "content": "package path\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\n// Base returns the last element of path.\n// Trailing path separators are removed before extracting the last element.\n// If the path consists entirely of separators, Base returns a single separator.\nfunc Base(input string) string {\n\tvolumeName := filepath.VolumeName(input)\n\t// Strip trailing slashes.\n\tfor len(input) > 0 && IsSeparator(input[len(input)-1]) {\n\t\tinput = input[0 : len(input)-1]\n\t}\n\n\tif input == \"\" {\n\t\treturn Separator()\n\t}\n\n\tif volumeName == input {\n\t\treturn input\n\t}\n\n\t// Throw away volume name\n\tinput = input[len(filepath.VolumeName(input)):]\n\t// Find the last element\n\ti := len(input) - 1\n\tfor i >= 0 && !IsSeparator(input[i]) {\n\t\ti--\n\t}\n\n\tif i >= 0 {\n\t\tinput = input[i+1:]\n\t}\n\n\t// If empty now, it had only slashes.\n\tif input == \"\" {\n\t\treturn Separator()\n\t}\n\n\treturn input\n}\n\nfunc Clean(input string) string {\n\tif input == \"\" {\n\t\treturn input\n\t}\n\n\tcleaned := input\n\tseparator := Separator()\n\n\t// The prefix can be empty for a relative path.\n\tvar prefix string\n\tif IsSeparator(cleaned[0]) {\n\t\tprefix = separator\n\t}\n\n\tif runtime.GOOS == windows {\n\t\t// Normalize (forward) slashes to backslashes on Windows.\n\t\tcleaned = strings.ReplaceAll(cleaned, \"/\", `\\`)\n\n\t\t// Clean the prefix for a UNC path, if any.\n\t\tif regex.MatchString(`^\\\\{2}[^\\\\]+`, cleaned) {\n\t\t\tcleaned = strings.TrimPrefix(cleaned, `\\\\.\\UNC\\`)\n\t\t\tif cleaned == \"\" {\n\t\t\t\treturn cleaned\n\t\t\t}\n\t\t\tprefix = `\\\\`\n\t\t}\n\n\t\t// Always use an uppercase drive letter on Windows.\n\t\tdriveLetter, err := regex.GetCompiledRegex(`^[a-z]:`)\n\t\tif err == nil {\n\t\t\tcleaned = driveLetter.ReplaceAllStringFunc(cleaned, strings.ToUpper)\n\t\t}\n\t}\n\n\tsb := text.NewBuilder()\n\n\tsb.WriteString(prefix)\n\n\t// Clean slashes.\n\tmatches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\\%s]+)`, separator), cleaned)\n\tn := len(matches) - 1\n\tfor i, m := range matches {\n\t\tsb.WriteString(m[\"element\"])\n\t\tif i != n {\n\t\t\tsb.WriteString(separator)\n\t\t}\n\t}\n\n\treturn sb.String()\n}\n\nfunc ReplaceHomeDirPrefixWithTilde(path string) string {\n\thome := Home()\n\tif !strings.HasPrefix(path, home) {\n\t\treturn path\n\t}\n\n\trem := path[len(home):]\n\tif rem == \"\" || IsSeparator(rem[0]) {\n\t\treturn \"~\" + rem\n\t}\n\n\treturn path\n}\n\nfunc ReplaceTildePrefixWithHomeDir(path string) string {\n\tif !strings.HasPrefix(path, \"~\") {\n\t\treturn path\n\t}\n\n\trem := path[1:]\n\tif rem == \"\" || IsSeparator(rem[0]) {\n\t\treturn Home() + rem\n\t}\n\n\treturn path\n}\n"
  },
  {
    "path": "src/runtime/path/home.go",
    "content": "package path\n\nimport (\n\t\"os\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc Home() string {\n\thome := os.Getenv(\"HOME\")\n\tdefer func() {\n\t\tlog.Debug(home)\n\t}()\n\n\tif len(home) > 0 {\n\t\treturn home\n\t}\n\n\t// fallback to older implementations on Windows\n\thome = os.Getenv(\"HOMEDRIVE\") + os.Getenv(\"HOMEPATH\")\n\n\tif home == \"\" {\n\t\thome = os.Getenv(\"USERPROFILE\")\n\t}\n\n\treturn home\n}\n"
  },
  {
    "path": "src/runtime/path/separator.go",
    "content": "package path\n\nimport (\n\t\"runtime\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nconst (\n\twindows = \"windows\"\n)\n\nfunc Separator() string {\n\tdefer log.Trace(time.Now())\n\n\tif runtime.GOOS == windows {\n\t\treturn `\\`\n\t}\n\n\treturn \"/\"\n}\n\nfunc IsSeparator(c uint8) bool {\n\tif c == '/' {\n\t\treturn true\n\t}\n\n\tif runtime.GOOS == windows && c == '\\\\' {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/runtime/terminal.go",
    "content": "package runtime\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\thttplib \"net/http\"\n\t\"net/http/httputil\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\n\tdisk \"github.com/shirou/gopsutil/v4/disk\"\n\tload \"github.com/shirou/gopsutil/v4/load\"\n\tprocess \"github.com/shirou/gopsutil/v4/process\"\n)\n\ntype Terminal struct {\n\tCmdFlags *Flags\n\tcmdCache *cache.Command\n\tlsDirMap *maps.Concurrent[[]fs.DirEntry]\n\tcwd      string\n\thost     string\n\tnetworks []*Connection\n}\n\nfunc (term *Terminal) Init(flags *Flags) {\n\tdefer log.Trace(time.Now())\n\n\tterm.CmdFlags = flags\n\n\tif term.CmdFlags == nil {\n\t\tterm.CmdFlags = &Flags{}\n\t}\n\n\tterm.lsDirMap = maps.NewConcurrent[[]fs.DirEntry]()\n\n\tterm.setPromptCount()\n\n\tterm.setPwd()\n\n\tterm.cmdCache = &cache.Command{\n\t\tCommands: maps.NewConcurrent[string](),\n\t}\n}\n\nfunc (term *Terminal) Getenv(key string) string {\n\tdefer log.Trace(time.Now(), key)\n\tval := os.Getenv(key)\n\tlog.Debug(val)\n\treturn val\n}\n\nfunc (term *Terminal) Pwd() string {\n\treturn term.cwd\n}\n\nfunc (term *Terminal) setPwd() {\n\tdefer log.Trace(time.Now())\n\n\tcorrectPath := func(pwd string) string {\n\t\tif term.GOOS() != WINDOWS {\n\t\t\treturn pwd\n\t\t}\n\n\t\t// on Windows, and being case sensitive and not consistent and all, this gives silly issues\n\t\tdriveLetter, err := regex.GetCompiledRegex(`^[a-z]:`)\n\t\tif err == nil {\n\t\t\treturn driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)\n\t\t}\n\n\t\treturn pwd\n\t}\n\n\tif term.CmdFlags != nil && term.CmdFlags.PWD != \"\" {\n\t\tterm.cwd = path.Clean(term.CmdFlags.PWD)\n\t\tlog.Debug(term.cwd)\n\t\treturn\n\t}\n\n\tdir, err := os.Getwd()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn\n\t}\n\n\tterm.cwd = correctPath(dir)\n\tlog.Debug(term.cwd)\n}\n\nfunc (term *Terminal) HasFiles(pattern string) bool {\n\treturn term.HasFilesInDir(term.Pwd(), pattern)\n}\n\nfunc (term *Terminal) HasFilesInDir(dir, pattern string) bool {\n\tdefer log.Trace(time.Now(), pattern)\n\n\tfileSystem := os.DirFS(dir)\n\tvar dirEntries []fs.DirEntry\n\n\tif files, OK := term.lsDirMap.Get(dir); OK {\n\t\tdirEntries = files\n\t}\n\n\tif len(dirEntries) == 0 {\n\t\tvar err error\n\t\tdirEntries, err = fs.ReadDir(fileSystem, \".\")\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tlog.Debug(\"false\")\n\t\t\treturn false\n\t\t}\n\n\t\tterm.lsDirMap.Set(dir, dirEntries)\n\t}\n\n\tpattern = strings.ToLower(pattern)\n\n\tfor _, match := range dirEntries {\n\t\tif match.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tmatchFileName, err := filepath.Match(pattern, strings.ToLower(match.Name()))\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tlog.Debug(\"false\")\n\t\t\treturn false\n\t\t}\n\n\t\tif matchFileName {\n\t\t\tlog.Debug(\"true\")\n\t\t\treturn true\n\t\t}\n\t}\n\n\tlog.Debug(\"false\")\n\treturn false\n}\n\nfunc (term *Terminal) HasFileInParentDirs(pattern string, depth uint) bool {\n\tdefer log.Trace(time.Now(), pattern, fmt.Sprint(depth))\n\tcurrentFolder := term.Pwd()\n\n\tfor c := 0; c < int(depth); c++ {\n\t\tif term.HasFilesInDir(currentFolder, pattern) {\n\t\t\tlog.Debug(\"true\")\n\t\t\treturn true\n\t\t}\n\n\t\tif dir := filepath.Dir(currentFolder); dir != currentFolder {\n\t\t\tcurrentFolder = dir\n\t\t} else {\n\t\t\tlog.Debug(\"false\")\n\t\t\treturn false\n\t\t}\n\t}\n\tlog.Debug(\"false\")\n\treturn false\n}\n\nfunc (term *Terminal) HasFolder(folder string) bool {\n\tdefer log.Trace(time.Now(), folder)\n\tf, err := os.Stat(folder)\n\tif err != nil {\n\t\tlog.Debug(\"false\")\n\t\treturn false\n\t}\n\tisDir := f.IsDir()\n\tlog.Debugf(\"%t\", isDir)\n\treturn isDir\n}\n\nfunc (term *Terminal) ResolveSymlink(input string) (string, error) {\n\tdefer log.Trace(time.Now(), input)\n\tlink, err := filepath.EvalSymlinks(input)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\tlog.Debug(link)\n\treturn link, nil\n}\n\nfunc (term *Terminal) FileContent(file string) string {\n\tdefer log.Trace(time.Now(), file)\n\tif !filepath.IsAbs(file) {\n\t\tfile = filepath.Join(term.Pwd(), file)\n\t}\n\n\tcontent, err := os.ReadFile(file)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\"\n\t}\n\n\tfileContent := string(content)\n\tlog.Debug(fileContent)\n\n\treturn fileContent\n}\n\nfunc (term *Terminal) LsDir(input string) []fs.DirEntry {\n\tdefer log.Trace(time.Now(), input)\n\n\tentries, err := os.ReadDir(input)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil\n\t}\n\n\tlog.Debugf(\"%v\", entries)\n\treturn entries\n}\n\nfunc (term *Terminal) User() string {\n\tdefer log.Trace(time.Now())\n\tuser := os.Getenv(\"USER\")\n\tif user == \"\" {\n\t\tuser = os.Getenv(\"USERNAME\")\n\t}\n\tlog.Debug(user)\n\treturn user\n}\n\nfunc (term *Terminal) Host() (string, error) {\n\tdefer log.Trace(time.Now())\n\tif len(term.host) != 0 {\n\t\treturn term.host, nil\n\t}\n\n\thostName, err := os.Hostname()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\n\thostName = cleanHostName(hostName)\n\tlog.Debug(hostName)\n\tterm.host = hostName\n\n\treturn hostName, nil\n}\n\nfunc (term *Terminal) GOOS() string {\n\tdefer log.Trace(time.Now())\n\treturn runtime.GOOS\n}\n\nfunc (term *Terminal) Home() string {\n\treturn path.Home()\n}\n\nfunc (term *Terminal) RunCommand(command string, args ...string) (string, error) {\n\tdefer log.Trace(time.Now(), append([]string{command}, args...)...)\n\n\tif cacheCommand, ok := term.cmdCache.Get(command); ok {\n\t\tcommand = cacheCommand\n\t}\n\n\toutput, err := cmd.Run(command, args...)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tlog.Debug(output)\n\treturn output, err\n}\n\nfunc (term *Terminal) RunShellCommand(shell, command string) string {\n\tdefer log.Trace(time.Now())\n\n\tif out, err := term.RunCommand(shell, \"-c\", command); err == nil {\n\t\treturn out\n\t}\n\n\treturn \"\"\n}\n\nfunc (term *Terminal) CommandPath(command string) string {\n\tdefer log.Trace(time.Now(), command)\n\tif cmdPath, ok := term.cmdCache.Get(command); ok {\n\t\tlog.Debug(cmdPath)\n\t\treturn cmdPath\n\t}\n\n\tcmdPath, err := exec.LookPath(command)\n\tif err == nil {\n\t\tterm.cmdCache.Set(command, cmdPath)\n\t\tlog.Debug(cmdPath)\n\t\treturn cmdPath\n\t}\n\n\tlog.Error(err)\n\treturn \"\"\n}\n\nfunc (term *Terminal) HasCommand(command string) bool {\n\tdefer log.Trace(time.Now(), command)\n\n\tif cmdPath := term.CommandPath(command); cmdPath != \"\" {\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (term *Terminal) StatusCodes() (int, string) {\n\tdefer log.Trace(time.Now())\n\n\tif term.CmdFlags.Shell != CMD || !term.CmdFlags.NoExitCode {\n\t\treturn term.CmdFlags.ErrorCode, term.CmdFlags.PipeStatus\n\t}\n\n\terrorCode := term.Getenv(\"=ExitCode\")\n\tlog.Debug(errorCode)\n\tterm.CmdFlags.ErrorCode, _ = strconv.Atoi(errorCode)\n\n\treturn term.CmdFlags.ErrorCode, term.CmdFlags.PipeStatus\n}\n\nfunc (term *Terminal) ExecutionTime() float64 {\n\tdefer log.Trace(time.Now())\n\tif term.CmdFlags.ExecutionTime < 0 {\n\t\treturn 0\n\t}\n\treturn term.CmdFlags.ExecutionTime\n}\n\nfunc (term *Terminal) Flags() *Flags {\n\tdefer log.Trace(time.Now())\n\treturn term.CmdFlags\n}\n\nfunc (term *Terminal) Shell() string {\n\tdefer log.Trace(time.Now())\n\tif len(term.CmdFlags.Shell) != 0 {\n\t\treturn term.CmdFlags.Shell\n\t}\n\n\tlog.Debug(\"no shell name provided in flags, trying to detect it\")\n\n\tpid := os.Getppid()\n\tp, _ := process.NewProcess(int32(pid))\n\n\tname, err := p.Name()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn UNKNOWN\n\t}\n\n\tlog.Debug(\"process name: \" + name)\n\n\t// Cache the shell value to speed things up.\n\tterm.CmdFlags.Shell = strings.Trim(strings.TrimSuffix(name, \".exe\"), \" \")\n\treturn term.CmdFlags.Shell\n}\n\nfunc (term *Terminal) unWrapError(err error) error {\n\tcause := err\n\tfor {\n\t\ttype nested interface{ Unwrap() error }\n\t\tunwrap, ok := cause.(nested)\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\tcause = unwrap.Unwrap()\n\t}\n\treturn cause\n}\n\nfunc (term *Terminal) HTTPRequest(targetURL string, body io.Reader, timeout int, requestModifiers ...http.RequestModifier) ([]byte, error) {\n\tdefer log.Trace(time.Now(), targetURL)\n\n\tctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))\n\tdefer cncl()\n\n\trequest, err := httplib.NewRequestWithContext(ctx, httplib.MethodGet, targetURL, body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfor _, modifier := range requestModifiers {\n\t\tmodifier(request)\n\t}\n\n\tif term.CmdFlags.Debug {\n\t\tdump, _ := httputil.DumpRequestOut(request, true)\n\t\tlog.Debug(string(dump))\n\t}\n\n\tresponse, err := http.HTTPClient.Do(request)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, term.unWrapError(err)\n\t}\n\n\t// anything inside the range [200, 299] is considered a success\n\tif response.StatusCode < 200 || response.StatusCode >= 300 {\n\t\terr := &http.Error{\n\t\t\tStatusCode: response.StatusCode,\n\t\t}\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tdefer response.Body.Close()\n\n\tresponseBody, err := io.ReadAll(response.Body)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tlog.Debug(string(responseBody))\n\n\treturn responseBody, nil\n}\n\nfunc (term *Terminal) HasParentFilePath(parent string, followSymlinks bool) (*FileInfo, error) {\n\tdefer log.Trace(time.Now(), parent)\n\n\tpwd := term.Pwd()\n\tif followSymlinks {\n\t\tif actual, err := term.ResolveSymlink(pwd); err == nil {\n\t\t\tpwd = actual\n\t\t}\n\t}\n\n\tfor {\n\t\tfileSystem := os.DirFS(pwd)\n\t\tinfo, err := fs.Stat(fileSystem, parent)\n\t\tif err == nil {\n\t\t\treturn &FileInfo{\n\t\t\t\tParentFolder: pwd,\n\t\t\t\tPath:         filepath.Join(pwd, parent),\n\t\t\t\tIsDir:        info.IsDir(),\n\t\t\t}, nil\n\t\t}\n\n\t\tif !os.IsNotExist(err) {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tif dir := filepath.Dir(pwd); dir != pwd {\n\t\t\tpwd = dir\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Error(err)\n\t\treturn nil, errors.New(\"no match at root level\")\n\t}\n}\n\nfunc (term *Terminal) StackCount() int {\n\tdefer log.Trace(time.Now())\n\n\tif term.CmdFlags.StackCount < 0 {\n\t\treturn 0\n\t}\n\n\treturn term.CmdFlags.StackCount\n}\n\nfunc (term *Terminal) Logs() string {\n\treturn log.String()\n}\n\nfunc (term *Terminal) DirMatchesOneOf(dir string, regexes []string) (match bool) {\n\t// sometimes the function panics inside golang, we want to silence that error\n\t// and assume that there's no match. Not perfect, but better than crashing\n\t// for the time being until we figure out what the actual root cause is\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\tlog.Error(errors.New(\"panic\"))\n\t\t\tmatch = false\n\t\t}\n\t}()\n\tmatch = dirMatchesOneOf(dir, term.Home(), term.GOOS(), regexes)\n\treturn\n}\n\nfunc dirMatchesOneOf(dir, home, goos string, regexes []string) bool {\n\tif len(regexes) == 0 {\n\t\treturn false\n\t}\n\n\tif goos == WINDOWS {\n\t\tdir = strings.ReplaceAll(dir, \"\\\\\", \"/\")\n\t\thome = strings.ReplaceAll(home, \"\\\\\", \"/\")\n\t}\n\n\tfor _, element := range regexes {\n\t\tnormalized := strings.ReplaceAll(element, \"\\\\\\\\\", \"/\")\n\t\tif strings.HasPrefix(normalized, \"~\") {\n\t\t\trem := normalized[1:]\n\t\t\tif rem == \"\" || rem[0] == '/' {\n\t\t\t\tnormalized = home + rem\n\t\t\t}\n\t\t}\n\t\tpattern := fmt.Sprintf(\"^%s$\", normalized)\n\t\tif goos == WINDOWS || goos == DARWIN {\n\t\t\tpattern = \"(?i)\" + pattern\n\t\t}\n\t\tmatched := regex.MatchString(pattern, dir)\n\t\tif matched {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (term *Terminal) setPromptCount() {\n\tdefer log.Trace(time.Now())\n\n\tvar count int\n\tif val, found := cache.Get[int](cache.Session, cache.PROMPTCOUNTCACHE); found {\n\t\tcount = val\n\t}\n\n\t// Only update the count if we're generating a primary prompt.\n\tif term.CmdFlags.Type == PRIMARY {\n\t\tcount++\n\t\tcache.Set(cache.Session, cache.PROMPTCOUNTCACHE, count, cache.ONEDAY)\n\t}\n\n\tterm.CmdFlags.PromptCount = count\n}\n\nfunc (term *Terminal) CursorPosition() (row, col int) {\n\tif number, err := strconv.Atoi(term.Getenv(\"POSH_CURSOR_LINE\")); err == nil {\n\t\trow = number\n\t}\n\n\tif number, err := strconv.Atoi(term.Getenv(\"POSH_CURSOR_COLUMN\")); err != nil {\n\t\tcol = number\n\t}\n\n\treturn\n}\n\nfunc (term *Terminal) SystemInfo() (*SystemInfo, error) {\n\ts := &SystemInfo{}\n\n\tmem, err := term.Memory()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ts.Memory = *mem\n\n\tloadStat, err := load.Avg()\n\tif err == nil {\n\t\ts.Load1 = loadStat.Load1\n\t\ts.Load5 = loadStat.Load5\n\t\ts.Load15 = loadStat.Load15\n\t}\n\n\tdiskIO, err := disk.IOCounters()\n\tif err == nil {\n\t\ts.Disks = diskIO\n\t}\n\treturn s, nil\n}\n\nfunc cleanHostName(hostName string) string {\n\tgarbage := []string{\n\t\t\".lan\",\n\t\t\".local\",\n\t\t\".localdomain\",\n\t}\n\tfor _, g := range garbage {\n\t\tif strings.HasSuffix(hostName, g) {\n\t\t\thostName = strings.Replace(hostName, g, \"\", 1)\n\t\t}\n\t}\n\treturn hostName\n}\n"
  },
  {
    "path": "src/runtime/terminal_darwin.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/battery\"\n)\n\nfunc mapMostLogicalState(state string) battery.State {\n\tswitch state {\n\tcase \"charging\":\n\t\treturn battery.Charging\n\tcase \"discharging\":\n\t\treturn battery.Discharging\n\tcase \"AC attached\":\n\t\treturn battery.NotCharging\n\tcase \"full\":\n\t\treturn battery.Full\n\tcase \"empty\":\n\t\treturn battery.Empty\n\tcase \"charged\":\n\t\treturn battery.Full\n\tdefault:\n\t\treturn battery.Unknown\n\t}\n}\n\nfunc (term *Terminal) parseBatteryOutput(output string) (*battery.Info, error) {\n\tmatches := regex.FindNamedRegexMatch(`(?P<PERCENTAGE>[0-9]{1,3})%; (?P<STATE>[a-zA-Z\\s]+);`, output)\n\tif len(matches) != 2 {\n\t\terr := errors.New(\"unable to find battery state based on output\")\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\tvar percentage int\n\tvar err error\n\tif percentage, err = strconv.Atoi(matches[\"PERCENTAGE\"]); err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, errors.New(\"unable to parse battery percentage\")\n\t}\n\treturn &battery.Info{\n\t\tPercentage: percentage,\n\t\tState:      mapMostLogicalState(matches[\"STATE\"]),\n\t}, nil\n}\n\nfunc (term *Terminal) BatteryState() (*battery.Info, error) {\n\tdefer log.Trace(time.Now())\n\toutput, err := term.RunCommand(\"pmset\", \"-g\", \"batt\")\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\tif !strings.Contains(output, \"Battery\") {\n\t\treturn nil, errors.New(\"no battery found\")\n\t}\n\treturn term.parseBatteryOutput(output)\n}\n"
  },
  {
    "path": "src/runtime/terminal_test.go",
    "content": "package runtime\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNormalHostName(t *testing.T) {\n\thostName := \"hello\"\n\tassert.Equal(t, hostName, cleanHostName(hostName))\n}\n\nfunc TestHostNameWithLocal(t *testing.T) {\n\thostName := \"hello.local\"\n\tassert.Equal(t, \"hello\", cleanHostName(hostName))\n}\n\nfunc TestHostNameWithLan(t *testing.T) {\n\thostName := \"hello.lan\"\n\tcleanHostName := cleanHostName(hostName)\n\tassert.Equal(t, \"hello\", cleanHostName)\n}\n\nfunc TestDirMatchesOneOf(t *testing.T) {\n\tcases := []struct {\n\t\tGOOS     string\n\t\tHomeDir  string\n\t\tDir      string\n\t\tPattern  string\n\t\tExpected bool\n\t}{\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill\", Pattern: \"/home/bill\", Expected: true},\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill/foo\", Pattern: \"~/foo\", Expected: true},\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill/foo\", Pattern: \"~/Foo\", Expected: false},\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill/foo\", Pattern: \"~\\\\\\\\foo\", Expected: true},\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill/foo/bar\", Pattern: \"~/fo.*\", Expected: true},\n\t\t{GOOS: LINUX, HomeDir: \"/home/bill\", Dir: \"/home/bill/foo\", Pattern: \"~/fo\\\\w\", Expected: true},\n\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\", Pattern: \"C:\\\\\\\\Users\\\\\\\\Bill\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\", Pattern: \"C:/Users/Bill\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\", Pattern: \"c:/users/bill\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\", Pattern: \"~\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\\\\Foo\", Pattern: \"~/Foo\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\\\\Foo\", Pattern: \"~/foo\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\\\\Foo\\\\Bar\", Pattern: \"~/fo.*\", Expected: true},\n\t\t{GOOS: WINDOWS, HomeDir: \"C:\\\\Users\\\\Bill\", Dir: \"C:\\\\Users\\\\Bill\\\\Foo\", Pattern: \"~/fo\\\\w\", Expected: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tgot := dirMatchesOneOf(tc.Dir, tc.HomeDir, tc.GOOS, []string{tc.Pattern})\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestDirMatchesOneOfRegexInverted(t *testing.T) {\n\t// detect panic(thrown by MustCompile)\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\t// display a message explaining omp failed(with the err)\n\t\t\tassert.Equal(t, \"regexp: Compile(`^(?!Projects[\\\\/]).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`\", err)\n\t\t}\n\t}()\n\t_ = dirMatchesOneOf(\"Projects/oh-my-posh\", \"\", LINUX, []string{\"(?!Projects[\\\\/]).*\"})\n}\n\nfunc TestDirMatchesOneOfRegexInvertedNonEscaped(t *testing.T) {\n\t// detect panic(thrown by MustCompile)\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\t// display a message explaining omp failed(with the err)\n\t\t\tassert.Equal(t, \"regexp: Compile(`^(?!Projects/).*$`): error parsing regexp: invalid or unsupported Perl syntax: `(?!`\", err)\n\t\t}\n\t}()\n\t_ = dirMatchesOneOf(\"Projects/oh-my-posh\", \"\", LINUX, []string{\"(?!Projects/).*\"})\n}\n"
  },
  {
    "path": "src/runtime/terminal_unix.go",
    "content": "//go:build !windows\n\npackage runtime\n\nimport (\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/shirou/gopsutil/v4/host\"\n\tmem \"github.com/shirou/gopsutil/v4/mem\"\n\tterminal \"github.com/wayneashleyberry/terminal-dimensions\"\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc (term *Terminal) Root() bool {\n\tdefer log.Trace(time.Now())\n\treturn os.Geteuid() == 0\n}\n\nfunc (term *Terminal) QueryWindowTitles(_, _ string) (string, error) {\n\treturn \"\", &NotImplemented{}\n}\n\nfunc (term *Terminal) IsWsl() bool {\n\tdefer log.Trace(time.Now())\n\tconst key = \"is_wsl\"\n\tif val, found := cache.Get[bool](cache.Device, key); found {\n\t\treturn val\n\t}\n\n\tvar val bool\n\tdefer func() {\n\t\tcache.Set(cache.Device, key, val, cache.INFINITE)\n\t}()\n\n\tval = term.HasCommand(\"wslpath\")\n\n\treturn val\n}\n\nfunc (term *Terminal) IsWsl2() bool {\n\tdefer log.Trace(time.Now())\n\tif !term.IsWsl() {\n\t\treturn false\n\t}\n\tuname := term.FileContent(\"/proc/sys/kernel/osrelease\")\n\treturn strings.Contains(uname, \"WSL2\")\n}\n\nfunc (term *Terminal) IsCygwin() bool {\n\tdefer log.Trace(time.Now())\n\treturn false\n}\n\nfunc (term *Terminal) TerminalWidth() (int, error) {\n\tdefer log.Trace(time.Now())\n\n\tif term.CmdFlags.TerminalWidth > 0 {\n\t\tlog.Debugf(\"terminal width: %d\", term.CmdFlags.TerminalWidth)\n\t\treturn term.CmdFlags.TerminalWidth, nil\n\t}\n\n\twidth, err := terminal.Width()\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\t// fetch width from the environment variable\n\t// in case the terminal width is not available\n\tif width == 0 {\n\t\ti, err := strconv.Atoi(term.Getenv(\"COLUMNS\"))\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\t\twidth = uint(i)\n\t}\n\n\tterm.CmdFlags.TerminalWidth = int(width)\n\tlog.Debugf(\"terminal width: %d\", term.CmdFlags.TerminalWidth)\n\n\t// Claude CLI has a 2 character padding on both sides\n\tif term.CmdFlags.Shell == \"claude\" {\n\t\tlog.Debug(\"adjusting terminal width for Claude CLI\")\n\t\tterm.CmdFlags.TerminalWidth -= 4\n\t}\n\n\treturn term.CmdFlags.TerminalWidth, err\n}\n\nfunc (term *Terminal) Platform() string {\n\tconst key = \"environment_platform\"\n\tif val, found := cache.Get[string](cache.Device, key); found {\n\t\treturn val\n\t}\n\n\tvar platform string\n\tdefer func() {\n\t\tcache.Set(cache.Device, key, platform, cache.INFINITE)\n\t}()\n\n\tif wsl := term.Getenv(\"WSL_DISTRO_NAME\"); len(wsl) != 0 {\n\t\tplatform, _, _ = strings.Cut(wsl, \"-\")\n\t\tplatform = strings.ToLower(platform)\n\t\tlog.Debug(platform)\n\t\treturn platform\n\t}\n\n\tplatform, _, _, _ = host.PlatformInformation()\n\tplatform = term.getSpecialLinuxDistros(platform)\n\n\tlog.Debug(platform)\n\treturn platform\n}\n\nfunc (term *Terminal) getSpecialLinuxDistros(platform string) string {\n\tlsbInfo := term.FileContent(\"/etc/lsb-release\")\n\n\tif platform == \"arch\" && strings.Contains(strings.ToLower(lsbInfo), \"manjaro\") {\n\t\t// validate for Manjaro\n\t\treturn \"manjaro\"\n\t}\n\n\tif platform == \"debian\" && strings.Contains(strings.ToLower(lsbInfo), \"zorin\") {\n\t\t// validate for Zorin OS\n\t\treturn \"zorin\"\n\t}\n\n\treturn platform\n}\n\nfunc (term *Terminal) WindowsRegistryKeyValue(_ string) (*WindowsRegistryValue, error) {\n\treturn nil, &NotImplemented{}\n}\n\nfunc (term *Terminal) InWSLSharedDrive() bool {\n\tif !term.IsWsl2() {\n\t\treturn false\n\t}\n\twindowsPath := term.ConvertToWindowsPath(term.Pwd())\n\treturn !strings.HasPrefix(windowsPath, `//wsl.localhost/`) && !strings.HasPrefix(windowsPath, `//wsl$/`)\n}\n\nfunc (term *Terminal) ConvertToWindowsPath(input string) string {\n\twindowsPath, err := term.RunCommand(\"wslpath\", \"-m\", input)\n\tif err == nil {\n\t\treturn windowsPath\n\t}\n\treturn input\n}\n\nfunc (term *Terminal) ConvertToLinuxPath(input string) string {\n\tif linuxPath, err := term.RunCommand(\"wslpath\", \"-u\", input); err == nil {\n\t\treturn linuxPath\n\t}\n\treturn input\n}\n\nfunc (term *Terminal) DirIsWritable(input string) bool {\n\tdefer log.Trace(time.Now(), input)\n\treturn unix.Access(input, unix.W_OK) == nil\n}\n\nfunc (term *Terminal) Connection(_ ConnectionType) (*Connection, error) {\n\t// added to disable the linting error, we can implement this later\n\tif len(term.networks) == 0 {\n\t\treturn nil, &NotImplemented{}\n\t}\n\n\treturn nil, &NotImplemented{}\n}\n\nfunc (term *Terminal) Memory() (*Memory, error) {\n\tm := &Memory{}\n\tmemStat, err := mem.VirtualMemory()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tm.PhysicalTotalMemory = memStat.Total\n\tm.PhysicalAvailableMemory = memStat.Available\n\tm.PhysicalFreeMemory = memStat.Free\n\n\tif memStat.Total > 0 {\n\t\tused := float64(memStat.Total) - float64(memStat.Available)\n\t\tif used < 0 {\n\t\t\tused = 0\n\t\t}\n\t\tm.PhysicalPercentUsed = used / float64(memStat.Total) * 100\n\t}\n\n\tswapStat, err := mem.SwapMemory()\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tm.SwapTotalMemory = swapStat.Total\n\tm.SwapFreeMemory = swapStat.Free\n\tm.SwapPercentUsed = swapStat.UsedPercent\n\treturn m, nil\n}\n"
  },
  {
    "path": "src/runtime/terminal_unix_test.go",
    "content": "//go:build !windows\n\npackage runtime\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMemoryPercentageCalculation(t *testing.T) {\n\tcases := []struct {\n\t\tName            string\n\t\tTotal           uint64\n\t\tAvailable       uint64\n\t\tExpectedPercent float64\n\t}{\n\t\t{\n\t\t\tName:            \"50% usage\",\n\t\t\tTotal:           8 * 1024 * 1024 * 1024,\n\t\t\tAvailable:       4 * 1024 * 1024 * 1024,\n\t\t\tExpectedPercent: 50.0,\n\t\t},\n\t\t{\n\t\t\tName:            \"37% usage (from issue)\",\n\t\t\tTotal:           8079691776,\n\t\t\tAvailable:       5093384192,\n\t\t\tExpectedPercent: 36.96,\n\t\t},\n\t\t{\n\t\t\tName:            \"25% usage\",\n\t\t\tTotal:           16 * 1024 * 1024 * 1024,\n\t\t\tAvailable:       12 * 1024 * 1024 * 1024,\n\t\t\tExpectedPercent: 25.0,\n\t\t},\n\t\t{\n\t\t\tName:            \"75% usage\",\n\t\t\tTotal:           8 * 1024 * 1024 * 1024,\n\t\t\tAvailable:       2 * 1024 * 1024 * 1024,\n\t\t\tExpectedPercent: 75.0,\n\t\t},\n\t\t{\n\t\t\tName:            \"0% usage\",\n\t\t\tTotal:           8 * 1024 * 1024 * 1024,\n\t\t\tAvailable:       8 * 1024 * 1024 * 1024,\n\t\t\tExpectedPercent: 0.0,\n\t\t},\n\t\t{\n\t\t\tName:            \"100% usage\",\n\t\t\tTotal:           8 * 1024 * 1024 * 1024,\n\t\t\tAvailable:       0,\n\t\t\tExpectedPercent: 100.0,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Name, func(t *testing.T) {\n\t\t\tvar percentUsed float64\n\t\t\tif tc.Total > 0 {\n\t\t\t\tpercentUsed = float64(tc.Total-tc.Available) / float64(tc.Total) * 100\n\t\t\t}\n\n\t\t\tassert.InDelta(t, tc.ExpectedPercent, percentUsed, 0.01, tc.Name)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/runtime/terminal_windows.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/Azure/go-ansiterm/winterm\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/registry\"\n)\n\nfunc (term *Terminal) Root() bool {\n\tdefer log.Trace(time.Now())\n\tvar sid *windows.SID\n\n\t// Although this looks scary, it is directly copied from the\n\t// official windows documentation. The Go API for this is a\n\t// direct wrap around the official C++ API.\n\t// See https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-checktokenmembership\n\terr := windows.AllocateAndInitializeSid(\n\t\t&windows.SECURITY_NT_AUTHORITY,\n\t\t2,\n\t\twindows.SECURITY_BUILTIN_DOMAIN_RID,\n\t\twindows.DOMAIN_ALIAS_RID_ADMINS,\n\t\t0, 0, 0, 0, 0, 0,\n\t\t&sid)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\tdefer func() {\n\t\t_ = windows.FreeSid(sid)\n\t}()\n\n\t// This appears to cast a null pointer so I'm not sure why this\n\t// works, but this guy says it does and it Works for Me™:\n\t// https://github.com/golang/go/issues/28804#issuecomment-438838144\n\ttoken := windows.Token(0)\n\n\tmember, err := token.IsMember(sid)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn member\n}\n\nfunc (term *Terminal) QueryWindowTitles(processName, windowTitleRegex string) (string, error) {\n\tdefer log.Trace(time.Now(), windowTitleRegex)\n\ttitle, err := queryWindowTitles(processName, windowTitleRegex)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\treturn title, err\n}\n\nfunc (term *Terminal) IsWsl() bool {\n\tdefer log.Trace(time.Now())\n\treturn false\n}\n\nfunc (term *Terminal) IsWsl2() bool {\n\tdefer log.Trace(time.Now())\n\treturn false\n}\n\nfunc (term *Terminal) IsCygwin() bool {\n\tdefer log.Trace(time.Now())\n\treturn len(term.Getenv(\"OSTYPE\")) != 0 || term.Getenv(\"BROWSER\") == \"cygstart\"\n}\n\nfunc (term *Terminal) TerminalWidth() (int, error) {\n\tdefer log.Trace(time.Now())\n\n\tif term.CmdFlags.TerminalWidth > 0 {\n\t\tlog.Debugf(\"terminal width: %d\", term.CmdFlags.TerminalWidth)\n\t\treturn term.CmdFlags.TerminalWidth, nil\n\t}\n\n\thandle, err := syscall.Open(\"CONOUT$\", syscall.O_RDWR, 0)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn 0, err\n\t}\n\n\tinfo, err := winterm.GetConsoleScreenBufferInfo(uintptr(handle))\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn 0, err\n\t}\n\n\tterm.CmdFlags.TerminalWidth = int(info.Size.X)\n\tlog.Debugf(\"terminal width: %d\", term.CmdFlags.TerminalWidth)\n\n\t// Claude CLI has a 2 character padding on both sides\n\tif term.CmdFlags.Shell == \"claude\" {\n\t\tlog.Debug(\"adjusting terminal width for Claude CLI\")\n\t\tterm.CmdFlags.TerminalWidth -= 4\n\t}\n\n\treturn term.CmdFlags.TerminalWidth, nil\n}\n\nfunc (term *Terminal) Platform() string {\n\treturn WINDOWS\n}\n\n// Takes a registry path to a key like\n//\n//\t\"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\EditionID\"\n//\n// The last part of the path is the key to retrieve.\n//\n// If the path ends in \"\\\", the \"(Default)\" key in that path is retrieved.\n//\n// Returns a variant type if successful; nil and an error if not.\nfunc (term *Terminal) WindowsRegistryKeyValue(input string) (*WindowsRegistryValue, error) {\n\tdefer log.Trace(time.Now(), input)\n\n\t// Format:\n\t// \"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\EditionID\"\n\t//   1  |                  2                         |   3\n\t//\n\t// Split into:\n\t//\n\t// 1. Root key - extract the root HKEY string and turn this into a handle to get started\n\t// 2. Path - open this path\n\t// 3. Key - get this key value\n\t//\n\t// If 3 is \"\" (i.e. the path ends with \"\\\"), then get (Default) key.\n\t//\n\trootKey, regPath, found := strings.Cut(input, `\\`)\n\tif !found {\n\t\terr := fmt.Errorf(\"Error, malformed registry path: '%s'\", input)\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tvar regKey string\n\tif !strings.HasSuffix(regPath, `\\`) {\n\t\tregKey = path.Base(regPath)\n\t\tif len(regKey) != 0 {\n\t\t\tregPath = strings.TrimSuffix(regPath, `\\`+regKey)\n\t\t}\n\t}\n\n\tvar key registry.Key\n\tswitch rootKey {\n\tcase \"HKCR\", \"HKEY_CLASSES_ROOT\":\n\t\tkey = windows.HKEY_CLASSES_ROOT\n\tcase \"HKCC\", \"HKEY_CURRENT_CONFIG\":\n\t\tkey = windows.HKEY_CURRENT_CONFIG\n\tcase \"HKCU\", \"HKEY_CURRENT_USER\":\n\t\tkey = windows.HKEY_CURRENT_USER\n\tcase \"HKLM\", \"HKEY_LOCAL_MACHINE\":\n\t\tkey = windows.HKEY_LOCAL_MACHINE\n\tcase \"HKU\", \"HKEY_USERS\":\n\t\tkey = windows.HKEY_USERS\n\tdefault:\n\t\terr := fmt.Errorf(\"Error, unknown registry key: '%s\", rootKey)\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tk, err := registry.OpenKey(key, regPath, registry.READ)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\t_, valType, err := k.GetValue(regKey, nil)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tvar regValue *WindowsRegistryValue\n\n\tswitch valType {\n\tcase windows.REG_SZ, windows.REG_EXPAND_SZ:\n\t\tvalue, _, _ := k.GetStringValue(regKey)\n\t\tregValue = &WindowsRegistryValue{ValueType: STRING, String: value}\n\tcase windows.REG_DWORD:\n\t\tvalue, _, _ := k.GetIntegerValue(regKey)\n\t\tregValue = &WindowsRegistryValue{ValueType: DWORD, DWord: value, String: fmt.Sprintf(\"0x%08X\", value)}\n\tcase windows.REG_QWORD:\n\t\tvalue, _, _ := k.GetIntegerValue(regKey)\n\t\tregValue = &WindowsRegistryValue{ValueType: QWORD, QWord: value, String: fmt.Sprintf(\"0x%016X\", value)}\n\tcase windows.REG_BINARY:\n\t\tvalue, _, _ := k.GetBinaryValue(regKey)\n\t\tregValue = &WindowsRegistryValue{ValueType: BINARY, String: string(value)}\n\t}\n\n\tif regValue == nil {\n\t\terrorLogMsg := fmt.Sprintf(\"Error, no formatter for type: %d\", valType)\n\t\treturn nil, errors.New(errorLogMsg)\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"%s(%s): %s\", regKey, regValue.ValueType, regValue.String))\n\treturn regValue, nil\n}\n\nfunc (term *Terminal) InWSLSharedDrive() bool {\n\treturn false\n}\n\nfunc (term *Terminal) ConvertToWindowsPath(input string) string {\n\treturn strings.ReplaceAll(input, `\\`, \"/\")\n}\n\nfunc (term *Terminal) ConvertToLinuxPath(input string) string {\n\treturn input\n}\n\nfunc (term *Terminal) DirIsWritable(input string) bool {\n\tdefer log.Trace(time.Now())\n\treturn term.isWriteable(input)\n}\n\nfunc (term *Terminal) Connection(connectionType ConnectionType) (*Connection, error) {\n\tif term.networks == nil {\n\t\tnetworks := term.getConnections()\n\t\tif len(networks) == 0 {\n\t\t\treturn nil, errors.New(\"no connections found\")\n\t\t}\n\n\t\tterm.networks = networks\n\t}\n\n\tfor _, network := range term.networks {\n\t\tif network.Type == connectionType {\n\t\t\treturn network, nil\n\t\t}\n\t}\n\n\tlog.Error(fmt.Errorf(\"network type '%s' not found\", connectionType))\n\treturn nil, &NotImplemented{}\n}\n"
  },
  {
    "path": "src/runtime/terminal_windows_nix.go",
    "content": "//go:build !darwin\n\npackage runtime\n\nimport (\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/battery\"\n)\n\nfunc (term *Terminal) BatteryState() (*battery.Info, error) {\n\tdefer log.Trace(time.Now())\n\tinfo, err := battery.Get()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\treturn info, nil\n}\n"
  },
  {
    "path": "src/runtime/win32_windows.go",
    "content": "package runtime\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\n// win32 specific code\n\n// win32 dll load and function definitions\nvar (\n\tuser32                       = syscall.NewLazyDLL(\"user32.dll\")\n\tprocEnumWindows              = user32.NewProc(\"EnumWindows\")\n\tprocGetWindowTextW           = user32.NewProc(\"GetWindowTextW\")\n\tprocGetWindowThreadProcessID = user32.NewProc(\"GetWindowThreadProcessId\")\n\n\tpsapi              = syscall.NewLazyDLL(\"psapi.dll\")\n\tgetModuleBaseNameA = psapi.NewProc(\"GetModuleBaseNameA\")\n\n\tiphlpapi     = syscall.NewLazyDLL(\"iphlpapi.dll\")\n\thGetIfTable2 = iphlpapi.NewProc(\"GetIfTable2\")\n)\n\n// enumWindows call enumWindows from user32 and returns all active windows\n// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumwindows\nfunc enumWindows(enumFunc, lparam uintptr) (err error) {\n\tr1, _, e1 := syscall.SyscallN(procEnumWindows.Addr(), enumFunc, lparam, 0)\n\tif r1 == 0 {\n\t\tif e1 != 0 {\n\t\t\terr = error(e1)\n\t\t} else {\n\t\t\terr = syscall.EINVAL\n\t\t}\n\t}\n\treturn\n}\n\n// getWindowText returns the title and text of a window from a window handle\n// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextw\nfunc getWindowText(hwnd syscall.Handle, str *uint16, maxCount int32) (length int32, err error) {\n\tr0, _, e1 := syscall.SyscallN(procGetWindowTextW.Addr(), uintptr(hwnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))\n\tlength = int32(r0)\n\tif length == 0 {\n\t\tif e1 != 0 {\n\t\t\terr = error(e1)\n\t\t} else {\n\t\t\terr = syscall.EINVAL\n\t\t}\n\t}\n\treturn\n}\n\nfunc getWindowFileName(handle syscall.Handle) (string, error) {\n\tvar pid int\n\t_, _, _ = procGetWindowThreadProcessID.Call(uintptr(handle), uintptr(unsafe.Pointer(&pid)))\n\tconst query = windows.PROCESS_QUERY_INFORMATION | windows.PROCESS_VM_READ\n\th, err := windows.OpenProcess(query, false, uint32(pid))\n\tif err != nil {\n\t\treturn \"\", errors.New(\"unable to open window process\")\n\t}\n\tbuf := [1024]byte{}\n\tlength, _, _ := getModuleBaseNameA.Call(uintptr(h), 0, uintptr(unsafe.Pointer(&buf)), 1024)\n\tfilename := string(buf[:length])\n\treturn strings.ToLower(filename), nil\n}\n\n// GetWindowTitle searches for a window attached to the pid\nfunc queryWindowTitles(processName, windowTitleRegex string) (string, error) {\n\tvar title string\n\t// callback for EnumWindows\n\tcb := syscall.NewCallback(func(handle syscall.Handle, _ uintptr) uintptr {\n\t\tfileName, err := getWindowFileName(handle)\n\t\tif err != nil {\n\t\t\t// ignore the error and continue enumeration\n\t\t\treturn 1\n\t\t}\n\t\tif processName != fileName {\n\t\t\t// ignore the error and continue enumeration\n\t\t\treturn 1\n\t\t}\n\t\tb := make([]uint16, 200)\n\t\t_, err = getWindowText(handle, &b[0], int32(len(b)))\n\t\tif err != nil {\n\t\t\t// ignore the error and continue enumeration\n\t\t\treturn 1\n\t\t}\n\t\ttitle = syscall.UTF16ToString(b)\n\t\tif regex.MatchString(windowTitleRegex, title) {\n\t\t\t// will cause EnumWindows to return 0 (error)\n\t\t\t// but we don't want to enumerate all windows since we got what we want\n\t\t\treturn 0\n\t\t}\n\t\treturn 1 // continue enumeration\n\t})\n\t// Enumerates all top-level windows on the screen\n\t// The error is not checked because if EnumWindows is stopped before enumerating all windows\n\t// it returns 0(error occurred) instead of 1(success)\n\t// In our case, title will equal \"\" or the title of the window anyway\n\terr := enumWindows(cb, 0)\n\tif title == \"\" {\n\t\tvar message string\n\t\tif err != nil {\n\t\t\tmessage = err.Error()\n\t\t}\n\t\treturn \"\", errors.New(\"no matching window title found\\n\" + message)\n\t}\n\treturn title, nil\n}\n\nvar (\n\tadvapi     = syscall.NewLazyDLL(\"advapi32.dll\")\n\tprocGetAce = advapi.NewProc(\"GetAce\")\n)\n\nconst (\n\tACCESS_DENIED_ACE_TYPE = 1\n)\n\ntype accessMask uint32\n\nfunc (m accessMask) canWrite() bool {\n\tallowed := []int{windows.GENERIC_WRITE, windows.WRITE_DAC, windows.WRITE_OWNER}\n\tfor _, v := range allowed {\n\t\tif m&accessMask(v) != 0 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (m accessMask) permissions() string {\n\tvar permissions []string\n\tif m&windows.GENERIC_READ != 0 {\n\t\tpermissions = append(permissions, \"GENERIC_READ\")\n\t}\n\tif m&windows.GENERIC_WRITE != 0 {\n\t\tpermissions = append(permissions, \"GENERIC_WRITE\")\n\t}\n\tif m&windows.GENERIC_EXECUTE != 0 {\n\t\tpermissions = append(permissions, \"GENERIC_EXECUTE\")\n\t}\n\tif m&windows.GENERIC_ALL != 0 {\n\t\tpermissions = append(permissions, \"GENERIC_ALL\")\n\t}\n\tif m&windows.WRITE_DAC != 0 {\n\t\tpermissions = append(permissions, \"WRITE_DAC\")\n\t}\n\tif m&windows.WRITE_OWNER != 0 {\n\t\tpermissions = append(permissions, \"WRITE_OWNER\")\n\t}\n\tif m&windows.SYNCHRONIZE != 0 {\n\t\tpermissions = append(permissions, \"SYNCHRONIZE\")\n\t}\n\tif m&windows.DELETE != 0 {\n\t\tpermissions = append(permissions, \"DELETE\")\n\t}\n\tif m&windows.READ_CONTROL != 0 {\n\t\tpermissions = append(permissions, \"READ_CONTROL\")\n\t}\n\tif m&windows.ACCESS_SYSTEM_SECURITY != 0 {\n\t\tpermissions = append(permissions, \"ACCESS_SYSTEM_SECURITY\")\n\t}\n\tif m&windows.MAXIMUM_ALLOWED != 0 {\n\t\tpermissions = append(permissions, \"MAXIMUM_ALLOWED\")\n\t}\n\treturn strings.Join(permissions, \"\\n\")\n}\n\ntype AccessAllowedAce struct {\n\tAceType    uint8\n\tAceFlags   uint8\n\tAceSize    uint16\n\tAccessMask accessMask\n\tSidStart   uint32\n}\n\nfunc getCurrentUser() (user *tokenUser, err error) {\n\ttoken := windows.GetCurrentProcessToken()\n\tdefer token.Close()\n\n\ttokenuser, err := token.GetTokenUser()\n\tif err != nil {\n\t\treturn\n\t}\n\ttokenGroups, err := token.GetTokenGroups()\n\tif err != nil {\n\t\treturn\n\t}\n\tuser = &tokenUser{\n\t\tsid:    tokenuser.User.Sid,\n\t\tgroups: tokenGroups.AllGroups(),\n\t}\n\treturn\n}\n\ntype tokenUser struct {\n\tsid    *windows.SID\n\tgroups []windows.SIDAndAttributes\n}\n\nfunc (u *tokenUser) isMemberOf(sid *windows.SID) bool {\n\tif u.sid.Equals(sid) {\n\t\treturn true\n\t}\n\tfor _, g := range u.groups {\n\t\tif g.Sid.Equals(sid) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (env *Terminal) isWriteable(folder string) bool {\n\tcu, err := getCurrentUser()\n\n\tif err != nil {\n\t\t// unable to get current user\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tsi, err := windows.GetNamedSecurityInfo(folder, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tdacl, _, err := si.DACL()\n\tif err != nil || dacl == nil {\n\t\t// no dacl implies full access\n\t\tlog.Debug(\"no dacl\")\n\t\treturn true\n\t}\n\n\trs := reflect.ValueOf(dacl).Elem()\n\taceCount := rs.Field(3).Uint()\n\n\tfor i := range aceCount {\n\t\tace := &AccessAllowedAce{}\n\n\t\tret, _, _ := procGetAce.Call(uintptr(unsafe.Pointer(dacl)), uintptr(i), uintptr(unsafe.Pointer(&ace)))\n\t\tif ret == 0 {\n\t\t\tlog.Debug(\"no ace found\")\n\t\t\treturn false\n\t\t}\n\n\t\taceSid := (*windows.SID)(unsafe.Pointer(&ace.SidStart))\n\n\t\tif !cu.isMemberOf(aceSid) {\n\t\t\tlog.Debug(\"not current user or in group\")\n\t\t\tcontinue\n\t\t}\n\n\t\tlog.Debug(fmt.Sprintf(\"current user is member of %s\", aceSid.String()))\n\n\t\t// this gets priority over the other access types\n\t\tif ace.AceType == ACCESS_DENIED_ACE_TYPE {\n\t\t\tlog.Debug(\"ACCESS_DENIED_ACE_TYPE\")\n\t\t\treturn false\n\t\t}\n\n\t\tlog.Debugf(\"%v\", ace.AccessMask.permissions())\n\t\tif ace.AccessMask.canWrite() {\n\t\t\tlog.Debug(\"user has write access\")\n\t\t\treturn true\n\t\t}\n\t}\n\tlog.Debug(\"no write access\")\n\treturn false\n}\n\nvar (\n\tkernel32             = syscall.NewLazyDLL(\"kernel32.dll\")\n\tglobalMemoryStatusEx = kernel32.NewProc(\"GlobalMemoryStatusEx\")\n)\n\ntype memoryStatusEx struct {\n\tLength               uint32\n\tMemoryLoad           uint32\n\tTotalPhys            uint64\n\tAvailPhys            uint64\n\tTotalPageFile        uint64\n\tAvailPageFile        uint64\n\tTotalVirtual         uint64\n\tAvailVirtual         uint64\n\tAvailExtendedVirtual uint64\n}\n\nfunc (env *Terminal) Memory() (*Memory, error) {\n\tvar memStat memoryStatusEx\n\tmemStat.Length = uint32(unsafe.Sizeof(memStat))\n\tr0, _, err := globalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memStat)))\n\tif r0 == 0 {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\treturn &Memory{\n\t\tPhysicalTotalMemory:     memStat.TotalPhys,\n\t\tPhysicalFreeMemory:      memStat.AvailPhys,\n\t\tPhysicalAvailableMemory: memStat.AvailPhys,\n\t\tPhysicalPercentUsed:     float64(memStat.MemoryLoad),\n\t}, nil\n}\n"
  },
  {
    "path": "src/segments/angular.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n)\n\ntype Angular struct {\n\tLanguage\n}\n\nfunc (a *Angular) Template() string {\n\treturn languageTemplate\n}\n\nfunc (a *Angular) Enabled() bool {\n\ta.extensions = []string{\"angular.json\"}\n\ta.tooling = map[string]*cmd{\n\t\t\"angular\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\tgetVersion: a.getVersion,\n\t\t},\n\t}\n\ta.defaultTooling = []string{\"angular\"}\n\ta.versionURLTemplate = \"https://github.com/angular/angular/releases/tag/{{.Full}}\"\n\n\treturn a.Language.Enabled()\n}\n\nfunc (a *Angular) getVersion() (string, error) {\n\treturn a.nodePackageVersion(filepath.Join(\"@angular\", \"core\"))\n}\n"
  },
  {
    "path": "src/segments/argocd.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/spf13/pflag\"\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\nconst (\n\targocdOptsEnv     = \"ARGOCD_OPTS\"\n\targocdInvalidYaml = \"invalid yaml\"\n\targocdNoCurrent   = \"no current context\"\n\n\tNameTemplate = \" {{ .Name }} \"\n)\n\ntype ArgocdContext struct {\n\tName   string `yaml:\"name\"`\n\tServer string `yaml:\"server\"`\n\tUser   string `yaml:\"user\"`\n}\n\ntype ArgocdConfig struct {\n\tCurrentContext string           `yaml:\"current-context\"`\n\tContexts       []*ArgocdContext `yaml:\"contexts\"`\n}\n\ntype Argocd struct {\n\tBase\n\n\tArgocdContext\n}\n\nfunc (a *Argocd) Template() string {\n\treturn NameTemplate\n}\n\nfunc (a *Argocd) Enabled() bool {\n\t// always parse config instead of using cli to save time\n\tconfigPath := a.getConfigPath()\n\tsucceeded, err := a.parseConfig(configPath)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\treturn succeeded\n}\n\nfunc (a *Argocd) getConfigPath() string {\n\tcp := path.Join(a.env.Home(), \".config\", \"argocd\", \"config\")\n\tcpo := a.getConfigFromOpts()\n\tif len(cpo) > 0 {\n\t\tcp = cpo\n\t}\n\treturn cp\n}\n\nfunc (a *Argocd) getConfigFromOpts() string {\n\t// don't exit/panic when encountering invalid flags\n\tflags := pflag.NewFlagSet(os.Args[0], pflag.ContinueOnError)\n\t// ignore other valid and invalid flags\n\tflags.ParseErrorsAllowlist.UnknownFlags = true\n\t// only care about config\n\tflags.String(\"config\", \"\", \"get config from opts\")\n\n\topts := a.env.Getenv(argocdOptsEnv)\n\t_ = flags.Parse(strings.Split(opts, \" \"))\n\treturn flags.Lookup(\"config\").Value.String()\n}\n\nfunc (a *Argocd) parseConfig(file string) (bool, error) {\n\tconfig := a.env.FileContent(file)\n\t// missing or empty file content\n\tif config == \"\" {\n\t\treturn false, errors.New(argocdInvalidYaml)\n\t}\n\n\tvar data ArgocdConfig\n\terr := yaml.Unmarshal([]byte(config), &data)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false, errors.New(argocdInvalidYaml)\n\t}\n\ta.Name = data.CurrentContext\n\tfor _, context := range data.Contexts {\n\t\tif context.Name == a.Name {\n\t\t\t// mandatory fields in yaml\n\t\t\tif context.Server == \"\" || context.User == \"\" {\n\t\t\t\treturn false, errors.New(argocdInvalidYaml)\n\t\t\t}\n\t\t\ta.Server = context.Server\n\t\t\ta.User = context.User\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, errors.New(argocdNoCurrent)\n}\n"
  },
  {
    "path": "src/segments/argocd_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tposhHome = \"/Users/posh\"\n)\n\nfunc TestArgocdGetConfigFromOpts(t *testing.T) {\n\tconfigFile := \"/Users/posh/.config/argocd/config\"\n\tcases := []struct {\n\t\tCase     string\n\t\tOpts     string\n\t\tExpected string\n\t}{\n\t\t{Case: \"invalid flag in opts\", Opts: \"--invalid\", Expected: \"\"},\n\t\t{Case: \"no config in opts\", Opts: \"--grpc-web\", Expected: \"\"},\n\t\t{\n\t\t\tCase:     \"config in opts\",\n\t\t\tOpts:     fmt.Sprintf(\"--grpc-web --config %s --plaintext\", configFile),\n\t\t\tExpected: configFile,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", argocdOptsEnv).Return(tc.Opts)\n\n\t\targocd := &Argocd{\n\t\t\tBase: Base{\n\t\t\t\tenv:     env,\n\t\t\t\toptions: options.Map{},\n\t\t\t},\n\t\t}\n\t\tconfig := argocd.getConfigFromOpts()\n\t\tassert.Equal(t, tc.Expected, config, tc.Case)\n\t}\n}\n\nfunc TestArgocdGetConfigPath(t *testing.T) {\n\tconfigFile := path.Join(poshHome, \".config\", \"argocd\", \"config\")\n\tcases := []struct {\n\t\tCase          string\n\t\tOpts          string\n\t\tExpected      string\n\t\tExpectedError string\n\t}{\n\t\t{Case: \"without opts\", Expected: configFile},\n\t\t{Case: \"with opts\", Opts: \"--config /etc/argocd/config\", Expected: \"/etc/argocd/config\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(poshHome)\n\t\tenv.On(\"Getenv\", argocdOptsEnv).Return(tc.Opts)\n\n\t\targocd := &Argocd{\n\t\t\tBase: Base{\n\t\t\t\tenv:     env,\n\t\t\t\toptions: options.Map{},\n\t\t\t},\n\t\t}\n\t\tassert.Equal(t, tc.Expected, argocd.getConfigPath())\n\t}\n}\n\nfunc TestArgocdParseConfig(t *testing.T) {\n\tconfigFile := \"/Users/posh/.config/argocd/config\"\n\tcases := []struct {\n\t\tExpectedContext ArgocdContext\n\t\tCase            string\n\t\tConfig          string\n\t\tExpectedError   string\n\t\tExpected        bool\n\t}{\n\t\t{Case: \"missing or empty yaml\", Config: \"\", ExpectedError: argocdInvalidYaml},\n\t\t{\n\t\t\tCase:          \"invalid yaml\",\n\t\t\tExpectedError: argocdInvalidYaml,\n\t\t\tConfig: `\n[context]\ncontext\n`,\n\t\t},\n\t\t{\n\t\t\tCase:          \"invalid config\",\n\t\t\tExpectedError: argocdInvalidYaml,\n\t\t\tConfig: `\ncontexts:\n  - name: context1\n    server: server1\n    user: user1\n  - name: context2\n    server: server2\n    userr: user2\ncurrent-context: context2\nservers:\n  - grpc-web: true\n    server: server1\n  - grpc-web: false\n    server: serve2\n`,\n\t\t},\n\t\t{\n\t\t\tCase:          \"no current context found\",\n\t\t\tExpectedError: argocdNoCurrent,\n\t\t\tConfig: `\ncontexts:\n  - name: context1\n    server: server1\n    user: user1\n  - name: context2\n    server: server2\n    user: user2\n`,\n\t\t},\n\t\t{\n\t\t\tCase:     \"current context found\",\n\t\t\tExpected: true,\n\t\t\tConfig: `\ncontexts:\n  - name: context1\n    server: server1\n    user: user1\n  - name: context2\n    server: server2\n    user: user2\ncurrent-context: context2\nservers:\n  - grpc-web: true\n    server: server1\n  - grpc-web: false\n    server: serve2\nusers:\n  - auth-token: authtoken1\n    name: user1\n    refresh-token: refreshtoken1\n  - auth-token: authtoken2\n    name: user2\n    refresh-token: refreshtoken2\n`,\n\t\t\tExpectedContext: ArgocdContext{\n\t\t\t\tName:   \"context2\",\n\t\t\t\tServer: \"server2\",\n\t\t\t\tUser:   \"user2\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"FileContent\", configFile).Return(tc.Config)\n\n\t\targocd := &Argocd{\n\t\t\tBase: Base{\n\t\t\t\tenv:     env,\n\t\t\t\toptions: options.Map{},\n\t\t\t},\n\t\t}\n\t\tif len(tc.ExpectedError) > 0 {\n\t\t\t_, err := argocd.parseConfig(configFile)\n\t\t\tassert.EqualError(t, err, tc.ExpectedError, tc.Case)\n\t\t\tcontinue\n\t\t}\n\t\tconfig, err := argocd.parseConfig(configFile)\n\t\tassert.NoErrorf(t, err, tc.Case)\n\t\tassert.Equal(t, tc.Expected, config, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedContext, argocd.ArgocdContext, tc.Case)\n\t}\n}\n\nfunc TestArgocdSegment(t *testing.T) {\n\tconfigFile := path.Join(poshHome, \".config\", \"argocd\", \"config\")\n\tcases := []struct {\n\t\tExpectedContext ArgocdContext\n\t\tCase            string\n\t\tOpts            string\n\t\tConfig          string\n\t\tTemplate        string\n\t\tExpectedString  string\n\t\tExpectedError   string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase: \"default template\",\n\t\t\tOpts: \"\",\n\t\t\tConfig: `\ncontexts:\n  - name: context1\n    server: server1\n    user: user1\n  - name: context2\n    server: server2\n    user: user2\ncurrent-context: context2\nservers:\n  - grpc-web: true\n    server: server1\n  - grpc-web: false\n    server: serve2\n`,\n\t\t\tExpectedString:  \"context2\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedContext: ArgocdContext{\n\t\t\t\tName:   \"context2\",\n\t\t\t\tServer: \"server2\",\n\t\t\t\tUser:   \"user2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"full template\",\n\t\t\tOpts: \"\",\n\t\t\tConfig: `\ncontexts:\n  - name: context1\n    server: server1\n    user: user1\n  - name: context2\n    server: server2\n    user: user2\ncurrent-context: context2\nservers:\n  - grpc-web: true\n    server: server1\n  - grpc-web: false\n    server: serve2\n`,\n\t\t\tTemplate:        \"{{ .Name }}:{{ .User}}@{{ .Server }}\",\n\t\t\tExpectedString:  \"context2:user2@server2\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedContext: ArgocdContext{\n\t\t\t\tName:   \"context2\",\n\t\t\t\tServer: \"server2\",\n\t\t\t\tUser:   \"user2\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:            \"broken config\",\n\t\t\tConfig:          `}`,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(poshHome)\n\t\tenv.On(\"Getenv\", argocdOptsEnv).Return(tc.Opts)\n\t\tenv.On(\"FileContent\", configFile).Return(tc.Config)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\targocd := &Argocd{}\n\t\targocd.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, argocd.Enabled(), tc.Case)\n\n\t\tif !tc.ExpectedEnabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedContext, argocd.ArgocdContext, tc.Case)\n\t\tif len(tc.Template) > 0 {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, argocd), tc.Case)\n\t\t} else {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, argocd.Template(), argocd), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/aurelia.go",
    "content": "package segments\n\ntype Aurelia struct {\n\tLanguage\n}\n\nfunc (a *Aurelia) Template() string {\n\treturn languageTemplate\n}\n\nfunc (a *Aurelia) Enabled() bool {\n\ta.extensions = []string{\"package.json\"}\n\ta.tooling = map[string]*cmd{\n\t\t\"aurelia\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)(-(?P<prerelease>[a-z]+).(?P<buildmetadata>[0-9]+))?)))`,\n\t\t\tgetVersion: a.getVersion,\n\t\t},\n\t}\n\ta.defaultTooling = []string{\"aurelia\"}\n\ta.versionURLTemplate = \"https://github.com/aurelia/aurelia/releases/tag/v{{ .Full }}\"\n\n\tif !a.hasNodePackage(\"aurelia\") {\n\t\treturn false\n\t}\n\n\treturn a.Language.Enabled()\n}\n\nfunc (a *Aurelia) getVersion() (string, error) {\n\treturn a.nodePackageVersion(\"aurelia\")\n}\n"
  },
  {
    "path": "src/segments/aws.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Aws struct {\n\tBase\n\n\tProfile string\n\tRegion  string\n}\n\nconst (\n\tdefaultUser = \"default\"\n)\n\nfunc (a *Aws) Template() string {\n\treturn \" {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \"\n}\n\nfunc (a *Aws) Enabled() bool {\n\tgetEnvFirstMatch := func(envs ...string) string {\n\t\tfor _, env := range envs {\n\t\t\tvalue := a.env.Getenv(env)\n\t\t\tif len(value) != 0 {\n\t\t\t\treturn value\n\t\t\t}\n\t\t}\n\n\t\treturn \"\"\n\t}\n\n\tdisplayDefaultUser := a.options.Bool(options.DisplayDefault, true)\n\ta.Profile = getEnvFirstMatch(\"AWS_VAULT\", \"AWS_DEFAULT_PROFILE\", \"AWS_PROFILE\")\n\tif !displayDefaultUser && a.Profile == defaultUser {\n\t\treturn false\n\t}\n\n\ta.Region = getEnvFirstMatch(\"AWS_REGION\", \"AWS_DEFAULT_REGION\")\n\tif len(a.Profile) != 0 && len(a.Region) != 0 {\n\t\treturn true\n\t}\n\n\tif a.Profile == \"\" && len(a.Region) != 0 && displayDefaultUser {\n\t\ta.Profile = defaultUser\n\t\treturn true\n\t}\n\n\ta.getConfigFileInfo()\n\tif !displayDefaultUser && a.Profile == defaultUser {\n\t\treturn false\n\t}\n\n\treturn len(a.Profile) != 0\n}\n\nfunc (a *Aws) getConfigFileInfo() {\n\tconfigPath := a.env.Getenv(\"AWS_CONFIG_FILE\")\n\tif configPath == \"\" {\n\t\tconfigPath = fmt.Sprintf(\"%s/.aws/config\", a.env.Home())\n\t}\n\n\tconfig := a.env.FileContent(configPath)\n\tconfigSection := \"[default]\"\n\tif len(a.Profile) != 0 {\n\t\tconfigSection = fmt.Sprintf(\"[profile %s]\", a.Profile)\n\t}\n\n\tconfigLines := strings.SplitSeq(config, \"\\n\")\n\tvar sectionActive bool\n\tfor line := range configLines {\n\t\tif strings.HasPrefix(line, configSection) {\n\t\t\tsectionActive = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif sectionActive && strings.HasPrefix(line, \"region\") {\n\t\t\tsplitted := strings.SplitN(line, \"=\", 3)\n\t\t\tif len(splitted) >= 2 {\n\t\t\t\ta.Region = strings.TrimSpace(splitted[1])\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\tif a.Profile == \"\" && len(a.Region) != 0 {\n\t\ta.Profile = defaultUser\n\t}\n}\n\nfunc (a *Aws) RegionAlias() string {\n\tif a.Region == \"\" {\n\t\treturn \"\"\n\t}\n\n\tsplitted := strings.Split(a.Region, \"-\")\n\tif len(splitted) < 2 {\n\t\treturn a.Region\n\t}\n\n\tsplitted[1] = regex.ReplaceAllString(`orth|outh|ast|est|entral`, splitted[1], \"\")\n\treturn strings.Join(splitted, \"\")\n}\n"
  },
  {
    "path": "src/segments/aws_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestAWSSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tProfile         string\n\t\tDefaultProfile  string\n\t\tVault           string\n\t\tRegion          string\n\t\tDefaultRegion   string\n\t\tConfigFile      string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t\tDisplayDefault  bool\n\t}{\n\t\t{Case: \"enabled with default user\", ExpectedString: \"default@eu-west\", Region: \"eu-west\", ExpectedEnabled: true, DisplayDefault: true},\n\t\t{Case: \"disabled with default user\", ExpectedString: \"default@eu-west\", Region: \"eu-west\", ExpectedEnabled: false, DisplayDefault: false},\n\t\t{Case: \"disabled\", ExpectedString: \"\", ExpectedEnabled: false},\n\t\t{Case: \"enabled with default user\", ExpectedString: \"default@eu-west\", Profile: \"default\", Region: \"eu-west\", ExpectedEnabled: true, DisplayDefault: true},\n\t\t{Case: \"enabled with default profile\", ExpectedString: \"default@eu-west\", DefaultProfile: \"default\", Region: \"eu-west\", ExpectedEnabled: true, DisplayDefault: true},\n\t\t{Case: \"disabled with default user\", ExpectedString: \"default\", Profile: \"default\", Region: \"eu-west\", ExpectedEnabled: false, DisplayDefault: false},\n\t\t{Case: \"enabled no region\", ExpectedString: \"company\", ExpectedEnabled: true, Profile: \"company\"},\n\t\t{Case: \"enabled with region\", ExpectedString: \"company@eu-west\", ExpectedEnabled: true, Profile: \"company\", Region: \"eu-west\", DefaultRegion: \"us-west\"},\n\t\t{Case: \"enabled with default region\", ExpectedString: \"company@us-west\", ExpectedEnabled: true, Profile: \"company\", DefaultRegion: \"us-west\"},\n\t\t{\n\t\t\tCase:            \"template: enabled no region\",\n\t\t\tExpectedString:  \"profile: company\",\n\t\t\tExpectedEnabled: true,\n\t\t\tProfile:         \"company\",\n\t\t\tTemplate:        \"profile: {{.Profile}}{{if .Region}} in {{.Region}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"template: enabled with region\",\n\t\t\tExpectedString:  \"profile: company in eu-west\",\n\t\t\tExpectedEnabled: true,\n\t\t\tProfile:         \"company\",\n\t\t\tRegion:          \"eu-west\",\n\t\t\tTemplate:        \"profile: {{.Profile}}{{if .Region}} in {{.Region}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"template: enabled with region alias that has compound cardinal direction\",\n\t\t\tExpectedString:  \"profile: company in apne3\",\n\t\t\tExpectedEnabled: true,\n\t\t\tProfile:         \"company\",\n\t\t\tRegion:          \"ap-northeast-3\",\n\t\t\tTemplate:        \"profile: {{.Profile}}{{if .Region}} in {{.RegionAlias}}{{end}}\",\n\t\t},\n\t\t{Case: \"template: invalid\", ExpectedString: \"{{ .Burp\", ExpectedEnabled: true, Profile: \"c\", Template: \"{{ .Burp\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"AWS_VAULT\").Return(tc.Vault)\n\t\tenv.On(\"Getenv\", \"AWS_PROFILE\").Return(tc.Profile)\n\t\tenv.On(\"Getenv\", \"AWS_DEFAULT_PROFILE\").Return(tc.DefaultProfile)\n\t\tenv.On(\"Getenv\", \"AWS_REGION\").Return(tc.Region)\n\t\tenv.On(\"Getenv\", \"AWS_DEFAULT_REGION\").Return(tc.DefaultRegion)\n\t\tenv.On(\"Getenv\", \"AWS_CONFIG_FILE\").Return(tc.ConfigFile)\n\t\tenv.On(\"FileContent\", \"/usr/home/.aws/config\").Return(\"\")\n\t\tenv.On(\"Home\").Return(\"/usr/home\")\n\t\tprops := options.Map{\n\t\t\toptions.DisplayDefault: tc.DisplayDefault,\n\t\t}\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\taws := &Aws{}\n\t\taws.Init(props, env)\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = aws.Template()\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, aws.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, aws), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/az.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Az struct {\n\tBase\n\n\tOrigin string\n\tAzureSubscription\n}\n\nconst (\n\tSource options.Option = \"source\"\n\n\tPwsh = \"pwsh\"\n\tCli  = \"cli\"\n\t// this deprecated value is used to support the old behavior of first_match\n\tFirstMatch = \"cli|pwsh\"\n\tazureEnv   = \"POSH_AZURE_SUBSCRIPTION\"\n)\n\ntype AzureConfig struct {\n\tInstallationID string               `json:\"installationId\"`\n\tSubscriptions  []*AzureSubscription `json:\"subscriptions\"`\n}\n\ntype AzureSubscription struct {\n\tUser              *AzureUser `json:\"user\"`\n\tID                string     `json:\"id\"`\n\tName              string     `json:\"name\"`\n\tState             string     `json:\"state\"`\n\tTenantID          string     `json:\"tenantId\"`\n\tTenantDisplayName string     `json:\"tenantDisplayName\"`\n\tEnvironmentName   string     `json:\"environmentName\"`\n\tHomeTenantID      string     `json:\"homeTenantId\"`\n\tManagedByTenants  []any      `json:\"managedByTenants\"`\n\tIsDefault         bool       `json:\"isDefault\"`\n}\n\ntype AzureUser struct {\n\tName string `json:\"name\"`\n\tType string `json:\"type\"`\n}\n\ntype AzurePowerShellSubscription struct {\n\tName    string `json:\"Name\"`\n\tAccount struct {\n\t\tType string `json:\"Type\"`\n\t} `json:\"Account\"`\n\tEnvironment struct {\n\t\tName string `json:\"Name\"`\n\t} `json:\"Environment\"`\n\tSubscription struct {\n\t\tID                 string `json:\"Id\"`\n\t\tName               string `json:\"Name\"`\n\t\tState              string `json:\"State\"`\n\t\tExtendedProperties struct {\n\t\t\tAccount string `json:\"Account\"`\n\t\t} `json:\"ExtendedProperties\"`\n\t} `json:\"Subscription\"`\n\tTenant struct {\n\t\tID   string `json:\"Id\"`\n\t\tName string `json:\"Name\"`\n\t} `json:\"Tenant\"`\n}\n\nfunc (a *Az) Template() string {\n\treturn NameTemplate\n}\n\nfunc (a *Az) Enabled() bool {\n\tsource := a.options.String(Source, FirstMatch)\n\n\t// migrate first_match\n\tif source == \"first_match\" {\n\t\tsource = FirstMatch\n\t}\n\n\tsources := strings.SplitSeq(source, \"|\")\n\n\tfor source := range sources {\n\t\tswitch source {\n\t\tcase Pwsh:\n\t\t\tif OK := a.getModuleSubscription(); OK {\n\t\t\t\treturn OK\n\t\t\t}\n\t\tcase Cli:\n\t\t\tif OK := a.getCLISubscription(); OK {\n\t\t\t\treturn OK\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (a *Az) FileContentWithoutBom(file string) string {\n\tconfig := a.env.FileContent(file)\n\tconst ByteOrderMark = \"\\ufeff\"\n\treturn strings.TrimLeft(config, ByteOrderMark)\n}\n\nfunc (a *Az) getCLISubscription() bool {\n\tcfg, err := a.findConfig(\"azureProfile.json\")\n\tif err != nil {\n\t\treturn false\n\t}\n\tcontent := a.FileContentWithoutBom(cfg)\n\tif content == \"\" {\n\t\treturn false\n\t}\n\tvar config AzureConfig\n\tif err := json.Unmarshal([]byte(content), &config); err != nil {\n\t\treturn false\n\t}\n\tfor _, subscription := range config.Subscriptions {\n\t\tif subscription.IsDefault {\n\t\t\ta.AzureSubscription = *subscription\n\t\t\ta.Origin = \"CLI\"\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc (a *Az) getModuleSubscription() bool {\n\tenvSubscription := a.env.Getenv(azureEnv)\n\tif envSubscription == \"\" {\n\t\treturn false\n\t}\n\n\tvar config AzurePowerShellSubscription\n\tif err := json.Unmarshal([]byte(envSubscription), &config); err != nil {\n\t\treturn false\n\t}\n\n\ta.IsDefault = true\n\ta.EnvironmentName = config.Environment.Name\n\ta.TenantID = config.Tenant.ID\n\ta.ID = config.Subscription.ID\n\ta.Name = config.Subscription.Name\n\ta.State = config.Subscription.State\n\ta.User = &AzureUser{\n\t\tName: config.Subscription.ExtendedProperties.Account,\n\t\tType: config.Account.Type,\n\t}\n\ta.TenantDisplayName = config.Tenant.Name\n\n\ta.Origin = \"PWSH\"\n\n\treturn true\n}\n\nfunc (a *Az) findConfig(fileName string) (string, error) {\n\tconfigDirs := []string{\n\t\ta.env.Getenv(\"AZURE_CONFIG_DIR\"),\n\t\tfilepath.Join(a.env.Home(), \".azure\"),\n\t\tfilepath.Join(a.env.Home(), \".Azure\"),\n\t}\n\tfor _, dir := range configDirs {\n\t\tif len(dir) != 0 && a.env.HasFilesInDir(dir, fileName) {\n\t\t\treturn filepath.Join(dir, fileName), nil\n\t\t}\n\t}\n\treturn \"\", errors.New(\"azure config dir not found\")\n}\n"
  },
  {
    "path": "src/segments/az_functions.go",
    "content": "package segments\n\ntype AzFunc struct {\n\tLanguage\n}\n\nfunc (az *AzFunc) Template() string {\n\treturn languageTemplate\n}\n\nfunc (az *AzFunc) Enabled() bool {\n\taz.extensions = []string{\"host.json\", \"local.settings.json\", \"function.json\"}\n\taz.tooling = map[string]*cmd{\n\t\t\"func\": {\n\t\t\texecutable: \"func\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>[0-9.]+)`,\n\t\t},\n\t}\n\taz.defaultTooling = []string{\"func\"}\n\n\treturn az.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/az_test.go",
    "content": "package segments\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestAzSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tSource          string\n\t\tExpectedEnabled bool\n\t\tHasCLI          bool\n\t\tHasPowerShell   bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no config files found\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az CLI Profile\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"AzureCliCloud\",\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasCLI:          true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az Pwsh Profile\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"AzurePoshCloud\",\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasPowerShell:   true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az Pwsh Profile\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"AzurePoshCloud\",\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasPowerShell:   true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Faulty template\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  template.IncorrectTemplate,\n\t\t\tTemplate:        \"{{ .Burp }}\",\n\t\t\tHasPowerShell:   true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"PWSH\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"PWSH\",\n\t\t\tTemplate:        \"{{ .Origin }}\",\n\t\t\tHasPowerShell:   true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"CLI\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"CLI\",\n\t\t\tTemplate:        \"{{ .Origin }}\",\n\t\t\tHasCLI:          true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az CLI Profile only\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"AzureCliCloud\",\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasCLI:          true,\n\t\t\tSource:          Cli,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az CLI Profile only - disabled\",\n\t\t\tExpectedEnabled: false,\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasCLI:          false,\n\t\t\tSource:          Cli,\n\t\t},\n\t\t{\n\t\t\tCase:            \"PowerShell Profile only\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"AzurePoshCloud\",\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tHasPowerShell:   true,\n\t\t\tSource:          Pwsh,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az CLI Profile only - disabled\",\n\t\t\tExpectedEnabled: false,\n\t\t\tTemplate:        \"{{ .EnvironmentName }}\",\n\t\t\tSource:          Pwsh,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Az CLI account type\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"user\",\n\t\t\tTemplate:        \"{{ .User.Type }}\",\n\t\t\tHasCLI:          true,\n\t\t\tSource:          Cli,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(poshHome)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\tvar azureProfile, azureRmContext string\n\n\t\tif tc.HasCLI {\n\t\t\tcontent, _ := os.ReadFile(\"../test/azureProfile.json\")\n\t\t\tazureProfile = string(content)\n\t\t}\n\t\tif tc.HasPowerShell {\n\t\t\tcontent, _ := os.ReadFile(\"../test/AzureRmContext.json\")\n\t\t\tazureRmContext = string(content)\n\t\t}\n\n\t\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\t\tenv.On(\"FileContent\", filepath.Join(poshHome, \".azure\", \"azureProfile.json\")).Return(azureProfile)\n\t\tenv.On(\"Getenv\", \"POSH_AZURE_SUBSCRIPTION\").Return(azureRmContext)\n\t\tenv.On(\"Getenv\", \"AZURE_CONFIG_DIR\").Return(\"\")\n\n\t\tif tc.HasCLI {\n\t\t\tenv.On(\"HasFilesInDir\", filepath.Clean(\"/Users/posh/.azure\"), \"azureProfile.json\").Return(true)\n\t\t} else {\n\t\t\tenv.On(\"HasFilesInDir\", filepath.Clean(\"/Users/posh/.azure\"), \"azureProfile.json\").Return(false)\n\t\t\tenv.On(\"HasFilesInDir\", filepath.Clean(\"/Users/posh/.Azure\"), \"azureProfile.json\").Return(false)\n\t\t}\n\n\t\tif tc.Source == \"\" {\n\t\t\ttc.Source = FirstMatch\n\t\t}\n\n\t\taz := &Az{}\n\t\taz.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, az.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, az), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/azd.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Azd struct {\n\tBase\n\tAzdConfig\n}\n\ntype AzdConfig struct {\n\tDefaultEnvironment string `json:\"defaultEnvironment\"`\n\tVersion            int    `json:\"version\"`\n}\n\nfunc (t *Azd) Template() string {\n\treturn \" \\uebd8 {{ .DefaultEnvironment }} \"\n}\n\nfunc (t *Azd) Enabled() bool {\n\tvar parentFilePath string\n\n\tfolders := t.options.StringArray(LanguageFolders, []string{\".azure\"})\n\tfor _, folder := range folders {\n\t\tif file, err := t.env.HasParentFilePath(folder, false); err == nil {\n\t\t\tparentFilePath = file.ParentFolder\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif parentFilePath == \"\" {\n\t\tlog.Debug(\"no .azure folder found in parent directories\")\n\t\treturn false\n\t}\n\n\tdotAzureFolder := filepath.Join(parentFilePath, \".azure\")\n\tfiles := t.env.LsDir(dotAzureFolder)\n\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.EqualFold(file.Name(), \"config.json\") {\n\t\t\treturn t.TryReadConfigJSON(filepath.Join(dotAzureFolder, file.Name()))\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (t *Azd) TryReadConfigJSON(file string) bool {\n\tif file == \"\" {\n\t\treturn false\n\t}\n\n\tcontent := t.env.FileContent(file)\n\tvar config AzdConfig\n\tif err := json.Unmarshal([]byte(content), &config); err != nil {\n\t\treturn false\n\t}\n\n\tt.AzdConfig = config\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/azd_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestAzdSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t\tIsInited        bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no .azure directory found\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Environment located\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"TestEnvironment\",\n\t\t\tTemplate:        \"{{ .DefaultEnvironment }}\",\n\t\t\tIsInited:        true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\tif tc.IsInited {\n\t\t\tfileInfo := &runtime.FileInfo{\n\t\t\t\tPath:         \"test/.azure\",\n\t\t\t\tParentFolder: \"test\",\n\t\t\t\tIsDir:        true,\n\t\t\t}\n\t\t\tenv.On(\"HasParentFilePath\", \".azure\", false).Return(fileInfo, nil)\n\t\t\tdirEntries := []fs.DirEntry{\n\t\t\t\t&MockDirEntry{\n\t\t\t\t\tname:  \"config.json\",\n\t\t\t\t\tisDir: false,\n\t\t\t\t}, &MockDirEntry{\n\t\t\t\t\tname:  \"TestEnvironment\",\n\t\t\t\t\tisDir: true,\n\t\t\t\t},\n\t\t\t}\n\t\t\tenv.On(\"LsDir\", filepath.Join(\"test\", \".azure\")).Return(dirEntries, nil)\n\n\t\t\tenv.On(\"FileContent\", filepath.Join(\"test\", \".azure\", \"config.json\")).Return(`{\"version\": 1, \"defaultEnvironment\": \"TestEnvironment\"}`, nil)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \".azure\", false).Return(&runtime.FileInfo{}, errors.New(\"no such file or directory\"))\n\t\t}\n\n\t\tazd := Azd{}\n\t\tazd.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, azd.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, azd), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/base.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Base struct {\n\toptions options.Provider\n\tenv     runtime.Environment\n\n\tSegment *Segment\n}\n\ntype Segment struct {\n\tText  string\n\tIndex int\n}\n\nfunc (b *Base) Text() string {\n\treturn b.Segment.Text\n}\n\nfunc (b *Base) SetText(text string) {\n\tb.Segment.Text = text\n}\n\nfunc (b *Base) SetIndex(index int) {\n\tb.Segment.Index = index\n}\n\nfunc (b *Base) Init(opts options.Provider, env runtime.Environment) {\n\tb.Segment = &Segment{}\n\tb.options = opts\n\tb.env = env\n}\n\nfunc (b *Base) CacheKey() (string, bool) {\n\treturn \"\", false\n}\n"
  },
  {
    "path": "src/segments/battery.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/battery\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Battery struct {\n\tBase\n\tError string\n\tIcon  string\n\tbattery.Info\n}\n\nconst (\n\t// ChargingIcon to display when charging\n\tChargingIcon options.Option = \"charging_icon\"\n\t// DischargingIcon o display when discharging\n\tDischargingIcon options.Option = \"discharging_icon\"\n\t// ChargedIcon to display when fully charged\n\tChargedIcon options.Option = \"charged_icon\"\n\t// NotChargingIcon to display when on AC power\n\tNotChargingIcon options.Option = \"not_charging_icon\"\n)\n\nfunc (b *Battery) Template() string {\n\treturn \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }} \"\n}\n\nfunc (b *Battery) Enabled() bool {\n\t// disable in WSL1\n\tif b.env.IsWsl() && !b.env.IsWsl2() {\n\t\treturn false\n\t}\n\n\tinfo, err := b.env.BatteryState()\n\n\tif !b.enabledWhileError(err) {\n\t\treturn false\n\t}\n\n\tb.Info = *info\n\n\t// case on computer without batteries(no error, empty array)\n\tif err == nil && b.Percentage == 0 {\n\t\treturn false\n\t}\n\n\tswitch b.State {\n\tcase battery.Discharging:\n\t\tb.Icon = b.options.String(DischargingIcon, \"\")\n\tcase battery.NotCharging:\n\t\tb.Icon = b.options.String(NotChargingIcon, \"\")\n\tcase battery.Charging:\n\t\tb.Icon = b.options.String(ChargingIcon, \"\")\n\tcase battery.Full:\n\t\tb.Icon = b.options.String(ChargedIcon, \"\")\n\tcase battery.Empty, battery.Unknown:\n\t\treturn true\n\t}\n\treturn true\n}\n\nfunc (b *Battery) enabledWhileError(err error) bool {\n\tif err == nil {\n\t\treturn true\n\t}\n\tif _, ok := err.(*battery.NoBatteryError); ok {\n\t\treturn false\n\t}\n\tdisplayError := b.options.Bool(options.DisplayError, false)\n\tif !displayError {\n\t\treturn false\n\t}\n\tb.Error = err.Error()\n\t// On Windows, it sometimes errors when the battery is full.\n\t// This hack ensures we display a fully charged battery, even if\n\t// that state can be incorrect. It's better to \"ignore\" the error\n\t// than to not display the segment at all as that will confuse users.\n\tb.Percentage = 100\n\tb.State = battery.Full\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/bazel.go",
    "content": "package segments\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\ntype Bazel struct {\n\tIcon string\n\tLanguage\n}\n\nconst (\n\t// Bazel's icon\n\tIcon options.Option = \"icon\"\n)\n\nfunc (b *Bazel) Template() string {\n\treturn \" {{ if .Error }}{{ .Icon }} {{ .Error }}{{ else }}{{ url .Icon .URL }} {{ .Full }}{{ end }} \"\n}\n\nfunc (b *Bazel) Enabled() bool {\n\tb.extensions = []string{\"*.bazel\", \"*.bzl\", \"BUILD\", \"WORKSPACE\", \".bazelrc\", \".bazelversion\"}\n\tb.folders = []string{\"bazel-bin\", \"bazel-out\", \"bazel-testlogs\"}\n\tb.tooling = map[string]*cmd{\n\t\t\"bazel\": {\n\t\t\texecutable: \"bazel\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `bazel (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tb.defaultTooling = []string{\"bazel\"}\n\t// Use the correct URL for Bazel >5.4.1, since they do not have the docs subdomain.\n\tb.versionURLTemplate = \"https://{{ if lt .Major 6 }}docs.{{ end }}bazel.build/versions/{{ .Major }}.{{ .Minor }}.{{ .Patch }}\"\n\n\tb.Icon = b.options.String(Icon, \"\\ue63a\")\n\n\treturn b.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/bazel_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBazel(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t\tTemplate       string\n\t}{\n\t\t{Case: \"bazel 4.0.0\", ExpectedString: \"<LINK>https://docs.bazel.build/versions/4.0.0<TEXT>\\ue63a</TEXT></LINK> 4.0.0\", Version: \"bazel 4.0.0\", Template: \"\"},\n\t\t{Case: \"bazel 5.4.1\", ExpectedString: \"<LINK>https://docs.bazel.build/versions/5.4.1<TEXT>\\ue63a</TEXT></LINK> 5.4.1\", Version: \"bazel 5.4.1\", Template: \"\"},\n\t\t{Case: \"bazel 6.4.0\", ExpectedString: \"<LINK>https://bazel.build/versions/6.4.0<TEXT>\\ue63a</TEXT></LINK> 6.4.0\", Version: \"bazel 6.4.0\", Template: \"\"},\n\t\t{Case: \"bazel 7.1.1\", ExpectedString: \"<LINK>https://bazel.build/versions/7.1.1<TEXT>\\ue63a</TEXT></LINK> 7.1.1\", Version: \"bazel 7.1.1\", Template: \"\"},\n\t\t{Case: \"bazel 10.11.12\", ExpectedString: \"<LINK>https://bazel.build/versions/10.11.12<TEXT>\\ue63a</TEXT></LINK> 10.11.12\", Version: \"bazel 10.11.12\", Template: \"\"},\n\t\t{Case: \"\", ExpectedString: \"\\ue63a err parsing info from bazel with\", Version: \"\", Template: \"\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"bazel\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.bazel\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tprops[Icon] = \"\\ue63a\"\n\t\tb := &Bazel{}\n\t\tb.Init(props, env)\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, b.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, b.Template(), b), failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/brewfather.go",
    "content": "package segments\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net/http\"\n\t\"sort\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// segment struct, makes templating easier\ntype Brewfather struct {\n\tBase\n\n\tDaysBottledOrFermented *uint\n\tTemperatureTrendIcon   string\n\tStatusIcon             string\n\tDayIcon                string\n\tURL                    string\n\tBatch\n\tReadingAge     int\n\tDaysFermenting uint\n\tDaysBottled    uint\n}\n\nconst (\n\tBFUserID  options.Option = \"user_id\"\n\tBFBatchID options.Option = \"batch_id\"\n\n\tBFDoubleUpIcon      options.Option = \"doubleup_icon\"\n\tBFSingleUpIcon      options.Option = \"singleup_icon\"\n\tBFFortyFiveUpIcon   options.Option = \"fortyfiveup_icon\"\n\tBFFlatIcon          options.Option = \"flat_icon\"\n\tBFFortyFiveDownIcon options.Option = \"fortyfivedown_icon\"\n\tBFSingleDownIcon    options.Option = \"singledown_icon\"\n\tBFDoubleDownIcon    options.Option = \"doubledown_icon\"\n\n\tBFPlanningStatusIcon     options.Option = \"planning_status_icon\"\n\tBFBrewingStatusIcon      options.Option = \"brewing_status_icon\"\n\tBFFermentingStatusIcon   options.Option = \"fermenting_status_icon\"\n\tBFConditioningStatusIcon options.Option = \"conditioning_status_icon\"\n\tBFCompletedStatusIcon    options.Option = \"completed_status_icon\"\n\tBFArchivedStatusIcon     options.Option = \"archived_status_icon\"\n\n\tBFDayIcon options.Option = \"day_icon\"\n\n\tBFStatusPlanning     string = \"Planning\"\n\tBFStatusBrewing      string = \"Brewing\"\n\tBFStatusFermenting   string = \"Fermenting\"\n\tBFStatusConditioning string = \"Conditioning\"\n\tBFStatusCompleted    string = \"Completed\"\n\tBFStatusArchived     string = \"Archived\"\n)\n\n// Returned from https://api.brewfather.app/v1/batches/batch_id/readings\ntype BatchReading struct {\n\tComment     string  `json:\"comment\"`\n\tDeviceType  string  `json:\"type\"`\n\tDeviceID    string  `json:\"id\"`\n\tGravity     float64 `json:\"sg\"`\n\tTemperature float64 `json:\"temp\"`\n\tTimepoint   int64   `json:\"timepoint\"`\n\tTime        int64   `json:\"time\"`\n}\ntype Batch struct {\n\tReading   *BatchReading\n\tStatus    string `json:\"status\"`\n\tBatchName string `json:\"name\"`\n\tRecipe    struct {\n\t\tName string `json:\"name\"`\n\t} `json:\"recipe\"`\n\tBatchNumber      int     `json:\"batchNo\"`\n\tBrewDate         int64   `json:\"brewDate\"`\n\tFermentStartDate int64   `json:\"fermentationStartDate\"`\n\tBottlingDate     int64   `json:\"bottlingDate\"`\n\tMeasuredOg       float64 `json:\"measuredOg\"`\n\tMeasuredFg       float64 `json:\"measuredFg\"`\n\tMeasuredAbv      float64 `json:\"measuredAbv\"`\n\tTemperatureTrend float64\n}\n\nfunc (bf *Brewfather) Template() string {\n\treturn \" {{ .StatusIcon }} {{ if .DaysBottledOrFermented }}{{ .DaysBottledOrFermented }}{{ .DayIcon }} {{ end }}{{ url .Recipe.Name .URL }} {{ printf \\\"%.1f\\\" .MeasuredAbv }}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\") }} {{ printf \\\"%.3f\\\" .Reading.Gravity }} {{ .Reading.Temperature }}\\u00b0 {{ .TemperatureTrendIcon }}{{ end }} \" //nolint:lll\n}\n\nfunc (bf *Brewfather) Enabled() bool {\n\tdata, err := bf.getResult()\n\tif err != nil {\n\t\treturn false\n\t}\n\tbf.Batch = *data\n\n\tif bf.Reading != nil {\n\t\treadingDate := time.UnixMilli(bf.Reading.Time)\n\t\tbf.ReadingAge = int(time.Since(readingDate).Hours())\n\t} else {\n\t\tbf.ReadingAge = -1\n\t}\n\n\tbf.TemperatureTrendIcon = bf.getTrendIcon(bf.TemperatureTrend)\n\tbf.StatusIcon = bf.getBatchStatusIcon(data.Status)\n\n\tfermStartDate := time.UnixMilli(bf.FermentStartDate)\n\tbottlingDate := time.UnixMilli(bf.BottlingDate)\n\n\tswitch bf.Status {\n\tcase BFStatusFermenting:\n\t\t// in the fermenter now, so relative to today.\n\t\tbf.DaysFermenting = uint(time.Since(fermStartDate).Hours() / 24)\n\t\tbf.DaysBottled = 0\n\t\tbf.DaysBottledOrFermented = &bf.DaysFermenting\n\tcase BFStatusConditioning, BFStatusCompleted, BFStatusArchived:\n\t\tbf.DaysFermenting = uint(bottlingDate.Sub(fermStartDate).Hours() / 24)\n\t\tbf.DaysBottled = uint(time.Since(bottlingDate).Hours() / 24)\n\t\tbf.DaysBottledOrFermented = &bf.DaysBottled\n\tdefault:\n\t\tbf.DaysFermenting = 0\n\t\tbf.DaysBottled = 0\n\t\tbf.DaysBottledOrFermented = nil\n\t}\n\n\t// URL property set to weblink to the full batch page\n\tbatchID := bf.options.String(BFBatchID, \"\")\n\tif len(batchID) > 0 {\n\t\tbf.URL = fmt.Sprintf(\"https://web.brewfather.app/tabs/batches/batch/%s\", batchID)\n\t}\n\n\tbf.DayIcon = bf.options.String(BFDayIcon, \"d\")\n\n\treturn true\n}\n\nfunc (bf *Brewfather) getTrendIcon(trend float64) string {\n\t// Not a fan of this logic - wondering if Go lets us do something cleaner...\n\tif trend >= 0 {\n\t\tif trend > 4 {\n\t\t\treturn bf.options.String(BFDoubleUpIcon, \"↑↑\")\n\t\t}\n\n\t\tif trend > 2 {\n\t\t\treturn bf.options.String(BFSingleUpIcon, \"↑\")\n\t\t}\n\n\t\tif trend > 0.5 {\n\t\t\treturn bf.options.String(BFFortyFiveUpIcon, \"↗\")\n\t\t}\n\n\t\treturn bf.options.String(BFFlatIcon, \"→\")\n\t}\n\n\tif trend < -4 {\n\t\treturn bf.options.String(BFDoubleDownIcon, \"↓↓\")\n\t}\n\n\tif trend < -2 {\n\t\treturn bf.options.String(BFSingleDownIcon, \"↓\")\n\t}\n\n\tif trend < -0.5 {\n\t\treturn bf.options.String(BFFortyFiveDownIcon, \"↘\")\n\t}\n\n\treturn bf.options.String(BFFlatIcon, \"→\")\n}\n\nfunc (bf *Brewfather) getBatchStatusIcon(batchStatus string) string {\n\tswitch batchStatus {\n\tcase BFStatusPlanning:\n\t\treturn bf.options.String(BFPlanningStatusIcon, \"\\uF8EA\")\n\tcase BFStatusBrewing:\n\t\treturn bf.options.String(BFBrewingStatusIcon, \"\\uF7DE\")\n\tcase BFStatusFermenting:\n\t\treturn bf.options.String(BFFermentingStatusIcon, \"\\uF499\")\n\tcase BFStatusConditioning:\n\t\treturn bf.options.String(BFConditioningStatusIcon, \"\\uE372\")\n\tcase BFStatusCompleted:\n\t\treturn bf.options.String(BFCompletedStatusIcon, \"\\uF7A5\")\n\tcase BFStatusArchived:\n\t\treturn bf.options.String(BFArchivedStatusIcon, \"\\uF187\")\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (bf *Brewfather) getResult() (*Batch, error) {\n\tuserID := bf.options.Template(BFUserID, \"\", bf)\n\tif userID == \"\" {\n\t\treturn nil, errors.New(\"missing Brewfather user id (user_id)\")\n\t}\n\n\tapiKey := bf.options.Template(APIKey, \"\", bf)\n\tif apiKey == \"\" {\n\t\treturn nil, errors.New(\"missing Brewfather api key (api_key)\")\n\t}\n\n\tbatchID := bf.options.Template(BFBatchID, \"\", bf)\n\tif batchID == \"\" {\n\t\treturn nil, errors.New(\"missing Brewfather batch id (batch_id)\")\n\t}\n\n\tauthString := fmt.Sprintf(\"%s:%s\", userID, apiKey)\n\tauthStringb64 := base64.StdEncoding.EncodeToString([]byte(authString))\n\tauthHeader := fmt.Sprintf(\"Basic %s\", authStringb64)\n\tbatchURL := fmt.Sprintf(\"https://api.brewfather.app/v1/batches/%s\", batchID)\n\tbatchReadingsURL := fmt.Sprintf(\"https://api.brewfather.app/v1/batches/%s/readings\", batchID)\n\n\thttpTimeout := bf.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\t// batch\n\taddAuthHeader := func(request *http.Request) {\n\t\trequest.Header.Add(\"authorization\", authHeader)\n\t}\n\n\tbody, err := bf.env.HTTPRequest(batchURL, nil, httpTimeout, addAuthHeader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar batch Batch\n\terr = json.Unmarshal(body, &batch)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// readings\n\tbody, err = bf.env.HTTPRequest(batchReadingsURL, nil, httpTimeout, addAuthHeader)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar arr []*BatchReading\n\terr = json.Unmarshal(body, &arr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(arr) > 0 {\n\t\t// could just take latest reading using their API, but that won't allow us to see trend - get 'em all and sort by time,\n\t\t// using two most recent for trend\n\t\tsort.Slice(arr, func(i, j int) bool {\n\t\t\treturn arr[i].Time > arr[j].Time\n\t\t})\n\n\t\t// Keep the latest one\n\t\tbatch.Reading = arr[0]\n\n\t\tif len(arr) > 1 {\n\t\t\tbatch.TemperatureTrend = arr[0].Temperature - arr[1].Temperature\n\t\t}\n\t}\n\n\treturn &batch, nil\n}\n\n// Unit conversion functions available to template.\nfunc (bf *Brewfather) DegCToF(degreesC float64) float64 {\n\treturn math.Round(10*((degreesC*1.8)+32)) / 10 // 1 decimal place\n}\n\nfunc (bf *Brewfather) DegCToKelvin(degreesC float64) float64 {\n\treturn math.Round(10*(degreesC+273.15)) / 10 // 1 decimal place, only addition, but just to be sure\n}\n\nfunc (bf *Brewfather) SGToBrix(sg float64) float64 {\n\t// from https://en.wikipedia.org/wiki/Brix#Specific_gravity_2\n\treturn math.Round(100*((182.4601*sg*sg*sg)-(775.6821*sg*sg)+(1262.7794*sg)-669.5622)) / 100\n}\n\nfunc (bf *Brewfather) SGToPlato(sg float64) float64 {\n\t// from https://en.wikipedia.org/wiki/Brix#Specific_gravity_2\n\treturn math.Round(100*((135.997*sg*sg*sg)-(630.272*sg*sg)+(1111.14*sg)-616.868)) / 100 // 2 decimal places\n}\n"
  },
  {
    "path": "src/segments/brewfather_test.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tBFFakeBatchID      = \"FAKE\"\n\tBFBatchURL         = \"https://api.brewfather.app/v1/batches/\" + BFFakeBatchID\n\tBFCacheKey         = BFBatchURL\n\tBFBatchReadingsURL = \"https://api.brewfather.app/v1/batches/\" + BFFakeBatchID + \"/readings\"\n)\n\nvar (\n\tTimeNow = time.Now()\n\t// Create a fake timeline for the fake json, all in Unix milliseconds, to be used in all fake json responses\n\tFakeBrewDate              = TimeNow.Add(-time.Hour * 24 * 20)\n\tFakeFermentationStartDate = FakeBrewDate.Add(time.Hour * 24)                   // 1 day after brew date = 19 days ago\n\tFakeReading1Date          = FakeFermentationStartDate.Add(time.Minute * 35)    // first reading 35 minutes\n\tFakeReading2Date          = FakeReading1Date.Add(time.Hour)                    // second reading 1 hour later\n\tFakeReading3Date          = FakeReading2Date.Add(time.Hour * 3)                // 3 hours after last reading, 454 hours ago\n\tFakeBottlingDate          = FakeFermentationStartDate.Add(time.Hour * 24 * 14) // 14 days after ferm date = 5 days ago\n\n\tBrewDateMillis      = FakeBrewDate.UnixMilli()\n\tFermStartDateMillis = FakeFermentationStartDate.UnixMilli()\n\tReading1DateMillis  = FakeReading1Date.UnixMilli()\n\tReading2DateMillis  = FakeReading2Date.UnixMilli()\n\tReading3DateMillis  = FakeReading3Date.UnixMilli()\n\tBottlingDateMillis  = FakeBottlingDate.UnixMilli()\n\n\tBatchNumber = 18\n\tBatchName   = \"Batch\"\n\tRecipeName  = \"Fake Beer\"\n\tMeasuredAbv = 1.3\n)\n\nfunc createBatch(status string) *Batch {\n\treturn &Batch{\n\t\tStatus:           status,\n\t\tBatchNumber:      BatchNumber,\n\t\tBrewDate:         BrewDateMillis,\n\t\tFermentStartDate: FermStartDateMillis,\n\t\tBottlingDate:     BottlingDateMillis,\n\t\tBatchName:        BatchName,\n\t\tMeasuredAbv:      MeasuredAbv,\n\t\tRecipe: struct {\n\t\t\tName string `json:\"name\"`\n\t\t}{\n\t\t\tName: RecipeName,\n\t\t},\n\t}\n}\n\nfunc createReading(temp, gravity float64, millis int64) *BatchReading {\n\treturn &BatchReading{\n\t\tDeviceID:    \"manual\",\n\t\tTemperature: temp,\n\t\tComment:     \"\",\n\t\tGravity:     gravity,\n\t\tTime:        millis,\n\t\tDeviceType:  \"manual\",\n\t}\n}\n\nfunc TestBrewfatherSegment(t *testing.T) {\n\tcases := []struct {\n\t\tError                 error\n\t\tBatchResponse         *Batch\n\t\tCase                  string\n\t\tExpectedString        string\n\t\tTemplate              string\n\t\tBatchReadingsResponse []*BatchReading\n\t\tCacheTimeout          int\n\t\tExpectedEnabled       bool\n\t\tCacheFoundFail        bool\n\t}{\n\t\t{\n\t\t\tCase:                  \"Planning Status\",\n\t\t\tBatchResponse:         createBatch(BFStatusPlanning),\n\t\t\tBatchReadingsResponse: []*BatchReading{},\n\t\t\tTemplate:              \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:        \" Fake Beer 1.3%\",\n\t\t\tExpectedEnabled:       true,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Brewing Status\",\n\t\t\tBatchResponse:         createBatch(BFStatusBrewing),\n\t\t\tBatchReadingsResponse: []*BatchReading{},\n\t\t\tTemplate:              \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:        \" Fake Beer 1.3%\",\n\t\t\tExpectedEnabled:       true,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"Fermenting Status, no readings\",\n\t\t\tBatchResponse:         createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{},\n\t\t\tTemplate:              \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:        \" 19d Fake Beer 1.3%\",\n\t\t\tExpectedEnabled:       true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Fermenting Status, one reading\",\n\t\t\tBatchResponse: createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(19.5, 1.066, Reading1DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:  \" 19d Fake Beer 1.3%: 1.066 19.5° →\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Fermenting Status, two readings, temp trending up\",\n\t\t\tBatchResponse: createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(21.0, 1.063, Reading2DateMillis),\n\t\t\t\tcreateReading(19.5, 1.066, Reading1DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:  \" 19d Fake Beer 1.3%: 1.063 21° ↗\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Fermenting Status, three readings, temp trending hard down, include age of most recent reading\",\n\t\t\tBatchResponse: createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(15.0, 1.050, Reading3DateMillis),\n\t\t\t\tcreateReading(21.0, 1.063, Reading2DateMillis),\n\t\t\t\tcreateReading(19.5, 1.066, Reading1DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:  \" 451 19d Fake Beer 1.3%: 1.05 15° ↓↓\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Bad batch json, readings fine\",\n\t\t\tBatchResponse: nil,\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(15.0, 1.050, Reading3DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{.StatusIcon}} {{.ReadingAge}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:  \"\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Conditioning Status\",\n\t\t\tBatchResponse: createBatch(BFStatusConditioning),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(15.0, 1.050, Reading3DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}d {{end}}{{.Recipe.Name}} {{.MeasuredAbv}}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\")}}: {{.Reading.Gravity}} {{.Reading.Temperature}}° {{.TemperatureTrendIcon}}{{end}}\", //nolint:lll\n\t\t\tExpectedString:  \" 5d Fake Beer 1.3%\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Fermenting Status, test all unit conversions\",\n\t\t\tBatchResponse: createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(34.5, 1.066, Reading1DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{ if and (.Reading) (eq .Status \\\"Fermenting\\\") }}SG: ({{.Reading.Gravity}} Bx:{{.SGToBrix .Reading.Gravity}} P:{{.SGToPlato .Reading.Gravity}}), Temp: (C:{{.Reading.Temperature}} F:{{.DegCToF .Reading.Temperature}} K:{{.DegCToKelvin .Reading.Temperature}}){{end}}\", //nolint:lll\n\t\t\tExpectedString:  \"SG: (1.066 Bx:16.13 P:16.13), Temp: (C:34.5 F:94.1 K:307.7)\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:          \"Fermenting Status, test all unit conversions 2\",\n\t\t\tBatchResponse: createBatch(BFStatusFermenting),\n\t\t\tBatchReadingsResponse: []*BatchReading{\n\t\t\t\tcreateReading(3.5, 1.004, Reading1DateMillis),\n\t\t\t},\n\t\t\tTemplate:        \"{{ if and (.Reading) (eq .Status \\\"Fermenting\\\") }}SG: ({{.Reading.Gravity}} Bx:{{.SGToBrix .Reading.Gravity}} P:{{.SGToPlato .Reading.Gravity}}), Temp: (C:{{.Reading.Temperature}} F:{{.DegCToF .Reading.Temperature}} K:{{.DegCToKelvin .Reading.Temperature}}){{end}}\", //nolint:lll\n\t\t\tExpectedString:  \"SG: (1.004 Bx:1.03 P:1.03), Temp: (C:3.5 F:38.3 K:276.7)\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tprops := options.Map{\n\t\t\tBFBatchID: BFFakeBatchID,\n\t\t\tAPIKey:    \"FAKE\",\n\t\t\tBFUserID:  \"FAKE\",\n\t\t}\n\n\t\tvar batchJSON []byte\n\t\tvar err error\n\t\tif tc.BatchResponse != nil {\n\t\t\tbatchJSON, err = json.Marshal(tc.BatchResponse)\n\t\t\tassert.NoError(t, err)\n\t\t} else {\n\t\t\t// bad JSON\n\t\t\tbatchJSON = []byte(\"invalid json\")\n\t\t}\n\n\t\tbatchReadingsJSON, err := json.Marshal(tc.BatchReadingsResponse)\n\t\tassert.NoError(t, err)\n\n\t\tenv.On(\"HTTPRequest\", BFBatchURL).Return(batchJSON, tc.Error)\n\t\tenv.On(\"HTTPRequest\", BFBatchReadingsURL).Return(batchReadingsJSON, tc.Error)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\tbrew := &Brewfather{}\n\t\tbrew.Init(props, env)\n\n\t\tenabled := brew.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = brew.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, brew), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/buf.go",
    "content": "package segments\n\ntype Buf struct {\n\tLanguage\n}\n\nfunc (b *Buf) Template() string {\n\treturn languageTemplate\n}\n\nfunc (b *Buf) Enabled() bool {\n\tb.extensions = []string{\"buf.yaml\", \"buf.gen.yaml\", \"buf.work.yaml\"}\n\tb.tooling = map[string]*cmd{\n\t\t\"buf\": {\n\t\t\texecutable: \"buf\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tb.defaultTooling = []string{\"buf\"}\n\tb.versionURLTemplate = \"https://github.com/bufbuild/buf/releases/tag/v{{.Full}}\"\n\n\treturn b.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/buf_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBuf(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Buf 1.12.0\", ExpectedString: \"1.12.0\", Version: \"1.12.0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"buf\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"buf.yaml\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tb := &Buf{}\n\t\tb.Init(props, env)\n\t\tassert.True(t, b.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, b.Template(), b), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/bun.go",
    "content": "package segments\n\ntype Bun struct {\n\tLanguage\n}\n\nfunc (b *Bun) Template() string {\n\treturn languageTemplate\n}\n\nfunc (b *Bun) Enabled() bool {\n\tb.extensions = []string{\"bun.lockb\", \"bun.lock\"}\n\tb.tooling = map[string]*cmd{\n\t\t\"bun\": {\n\t\t\texecutable: \"bun\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tb.defaultTooling = []string{\"bun\"}\n\tb.versionURLTemplate = \"https://github.com/oven-sh/bun/releases/tag/bun-v{{.Full}}\"\n\n\treturn b.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/bun_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBun(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Bun 1.1.8\", ExpectedString: \"1.1.8\", Version: \"1.1.8\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"bun\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"bun.lockb\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tb := &Bun{}\n\t\tb.Init(props, env)\n\t\tassert.True(t, b.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, b.Template(), b), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/carbon_intensity.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype CarbonIntensity struct {\n\tBase\n\n\tTrendIcon string\n\n\tCarbonIntensityData\n}\n\ntype CarbonIntensityResponse struct {\n\tData []CarbonIntensityPeriod `json:\"data\"`\n}\n\ntype CarbonIntensityPeriod struct {\n\tIntensity *CarbonIntensityData `json:\"intensity\"`\n\tFrom      string               `json:\"from\"`\n\tTo        string               `json:\"to\"`\n}\n\ntype CarbonIntensityData struct {\n\tIndex    Index  `json:\"index\"`\n\tForecast Number `json:\"forecast\"`\n\tActual   Number `json:\"actual\"`\n}\n\ntype Number int\n\nfunc (n Number) String() string {\n\tif n == 0 {\n\t\treturn \"??\"\n\t}\n\n\treturn fmt.Sprintf(\"%d\", n)\n}\n\ntype Index string\n\nfunc (i Index) Icon() string {\n\tswitch i {\n\tcase \"very low\":\n\t\treturn \"↓↓\"\n\tcase \"low\":\n\t\treturn \"↓\"\n\tcase \"moderate\":\n\t\treturn \"•\"\n\tcase \"high\":\n\t\treturn \"↑\"\n\tcase \"very high\":\n\t\treturn \"↑↑\"\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (d *CarbonIntensity) Enabled() bool {\n\terr := d.setStatus()\n\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (d *CarbonIntensity) Template() string {\n\treturn \" CO₂ {{ .Index.Icon }}{{ .Actual.String }} {{ .TrendIcon }} {{ .Forecast.String }} \"\n}\n\nfunc (d *CarbonIntensity) getResult() (*CarbonIntensityResponse, error) {\n\tresponse := new(CarbonIntensityResponse)\n\turl := \"https://api.carbonintensity.org.uk/intensity\"\n\n\thttpTimeout := d.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tbody, err := d.env.HTTPRequest(url, nil, httpTimeout)\n\tif err != nil {\n\t\treturn new(CarbonIntensityResponse), err\n\t}\n\n\terr = json.Unmarshal(body, &response)\n\tif err != nil {\n\t\treturn new(CarbonIntensityResponse), err\n\t}\n\n\treturn response, nil\n}\n\nfunc (d *CarbonIntensity) setStatus() error {\n\tresponse, err := d.getResult()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(response.Data) == 0 {\n\t\td.Actual = 0\n\t\td.Forecast = 0\n\t\td.Index = \"??\"\n\t\td.TrendIcon = \"→\"\n\t\treturn nil\n\t}\n\n\td.CarbonIntensityData = *response.Data[0].Intensity\n\n\tif d.Forecast > d.Actual {\n\t\td.TrendIcon = \"↗\"\n\t}\n\n\tif d.Forecast < d.Actual {\n\t\td.TrendIcon = \"↘\"\n\t}\n\n\tif d.Forecast == d.Actual || d.Actual == 0 || d.Forecast == 0 {\n\t\td.TrendIcon = \"→\"\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/carbon_intensity_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tCARBONINTENSITYURL = \"https://api.carbonintensity.org.uk/intensity\"\n)\n\nfunc TestCarbonIntensitySegmentSingle(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tIndex           string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tActual          int\n\t\tForecast        int\n\t\tHasError        bool\n\t\tHasData         bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Very Low, Going Down\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          20,\n\t\t\tForecast:        10,\n\t\t\tIndex:           \"very low\",\n\t\t\tExpectedString:  \"CO₂ ↓↓20 ↘ 10\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Very Low, Staying Same\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          20,\n\t\t\tForecast:        20,\n\t\t\tIndex:           \"very low\",\n\t\t\tExpectedString:  \"CO₂ ↓↓20 → 20\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Very Low, Going Up\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          20,\n\t\t\tForecast:        30,\n\t\t\tIndex:           \"very low\",\n\t\t\tExpectedString:  \"CO₂ ↓↓20 ↗ 30\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Low, Going Down\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          100,\n\t\t\tForecast:        50,\n\t\t\tIndex:           \"low\",\n\t\t\tExpectedString:  \"CO₂ ↓100 ↘ 50\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Low, Staying Same\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          100,\n\t\t\tForecast:        100,\n\t\t\tIndex:           \"low\",\n\t\t\tExpectedString:  \"CO₂ ↓100 → 100\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Low, Going Up\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          100,\n\t\t\tForecast:        150,\n\t\t\tIndex:           \"low\",\n\t\t\tExpectedString:  \"CO₂ ↓100 ↗ 150\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Moderate, Going Down\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          150,\n\t\t\tForecast:        100,\n\t\t\tIndex:           \"moderate\",\n\t\t\tExpectedString:  \"CO₂ •150 ↘ 100\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Moderate, Staying Same\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          150,\n\t\t\tForecast:        150,\n\t\t\tIndex:           \"moderate\",\n\t\t\tExpectedString:  \"CO₂ •150 → 150\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Moderate, Going Up\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          150,\n\t\t\tForecast:        200,\n\t\t\tIndex:           \"moderate\",\n\t\t\tExpectedString:  \"CO₂ •150 ↗ 200\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"High, Going Down\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          200,\n\t\t\tForecast:        150,\n\t\t\tIndex:           \"high\",\n\t\t\tExpectedString:  \"CO₂ ↑200 ↘ 150\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"High, Staying Same\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          200,\n\t\t\tForecast:        200,\n\t\t\tIndex:           \"high\",\n\t\t\tExpectedString:  \"CO₂ ↑200 → 200\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"High, Going Up\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          200,\n\t\t\tForecast:        300,\n\t\t\tIndex:           \"high\",\n\t\t\tExpectedString:  \"CO₂ ↑200 ↗ 300\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Missing Actual\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          0, // Missing data will be parsed to the default value of 0\n\t\t\tForecast:        300,\n\t\t\tIndex:           \"high\",\n\t\t\tExpectedString:  \"CO₂ ↑?? → 300\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Missing Forecast\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          200,\n\t\t\tForecast:        0, // Missing data will be parsed to the default value of 0\n\t\t\tIndex:           \"high\",\n\t\t\tExpectedString:  \"CO₂ ↑200 → ??\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Missing Index\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         true,\n\t\t\tActual:          200,\n\t\t\tForecast:        300,\n\t\t\tIndex:           \"\", // Missing data will be parsed to the default value of \"\"\n\t\t\tExpectedString:  \"CO₂ 200 ↗ 300\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Missing Data\",\n\t\t\tHasError:        false,\n\t\t\tHasData:         false,\n\t\t\tActual:          0,\n\t\t\tForecast:        0,\n\t\t\tIndex:           \"\",\n\t\t\tExpectedString:  \"CO₂ ?? → ??\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Error\",\n\t\t\tHasError:        true,\n\t\t\tHasData:         false,\n\t\t\tActual:          0,\n\t\t\tForecast:        0,\n\t\t\tIndex:           \"\",\n\t\t\tExpectedString:  \"\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tvar props = options.Map{\n\t\t\toptions.HTTPTimeout: 5000,\n\t\t}\n\n\t\tjsonResponse := fmt.Sprintf(\n\t\t\t`{ \"data\": [ { \"from\": \"2023-10-27T12:30Z\", \"to\": \"2023-10-27T13:00Z\", \"intensity\": { \"forecast\": %d, \"actual\": %d, \"index\": \"%s\" } } ] }`,\n\t\t\ttc.Forecast, tc.Actual, tc.Index,\n\t\t)\n\n\t\tif !tc.HasData {\n\t\t\tjsonResponse = `{ \"data\": [] }`\n\t\t}\n\n\t\tif tc.HasError {\n\t\t\tjsonResponse = `{ \"error\": \"Something went wrong\" }`\n\t\t}\n\n\t\tresponseError := errors.New(\"Something went wrong\")\n\t\tif !tc.HasError {\n\t\t\tresponseError = nil\n\t\t}\n\n\t\tenv.On(\"HTTPRequest\", CARBONINTENSITYURL).Return([]byte(jsonResponse), responseError)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\n\t\td := &CarbonIntensity{}\n\t\td.Init(props, env)\n\n\t\tenabled := d.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = d.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, d), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/cds.go",
    "content": "package segments\n\ntype Cds struct {\n\tLanguage\n\tHasDependency bool\n}\n\nfunc (c *Cds) Template() string {\n\treturn languageTemplate\n}\n\nfunc (c *Cds) Enabled() bool {\n\tc.extensions = []string{\".cdsrc.json\", \".cdsrc-private.json\", \"*.cds\"}\n\tc.tooling = map[string]*cmd{\n\t\t\"cds\": {\n\t\t\texecutable: \"cds\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `@sap/cds: (?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tc.defaultTooling = []string{\"cds\"}\n\tc.Language.loadContext = c.loadContext\n\tc.Language.inContext = c.inContext\n\tc.displayMode = c.options.String(DisplayMode, DisplayModeContext)\n\n\treturn c.Language.Enabled()\n}\n\nfunc (c *Cds) loadContext() {\n\tif !c.hasNodePackage(\"@sap/cds\") {\n\t\treturn\n\t}\n\n\tc.HasDependency = true\n}\n\nfunc (c *Cds) inContext() bool {\n\treturn c.HasDependency\n}\n"
  },
  {
    "path": "src/segments/cds_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCdsSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tTemplate       string\n\t\tVersion        string\n\t\tPackageJSON    string\n\t\tDisplayMode    string\n\t}{\n\t\t{\n\t\t\tCase:           \"1) cds 5.5.0 - file .cdsrc.json present\",\n\t\t\tExpectedString: \"5.5.0\",\n\t\t\tVersion:        \"@sap/cds: 5.5.0\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:           \"2) cds 5.5.1 - file some.cds\",\n\t\t\tExpectedString: \"5.5.1\",\n\t\t\tVersion:        \"@sap/cds: 5.5.1\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:           \"4) cds 5.5.3 - package.json dependency\",\n\t\t\tExpectedString: \"5.5.3\",\n\t\t\tVersion:        \"@sap/cds: 5.5.3\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tPackageJSON:    \"{ \\\"name\\\": \\\"my-app\\\",\\\"dependencies\\\": { \\\"@sap/cds\\\": \\\"^5\\\" } }\",\n\t\t\tDisplayMode:    DisplayModeContext,\n\t\t},\n\t\t{\n\t\t\tCase:           \"4) cds 5.5.4 - package.json dependency, major + minor\",\n\t\t\tExpectedString: \"5.5\",\n\t\t\tTemplate:       \"{{ .Major }}.{{ .Minor }}\",\n\t\t\tVersion:        \"@sap/cds: 5.5.4\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tPackageJSON:    \"{ \\\"name\\\": \\\"my-app\\\",\\\"dependencies\\\": { \\\"@sap/cds\\\": \\\"^5\\\" } }\",\n\t\t\tDisplayMode:    DisplayModeContext,\n\t\t},\n\t\t{\n\t\t\tCase:           \"6) cds 5.5.9 - display always\",\n\t\t\tExpectedString: \"5.5.9\",\n\t\t\tVersion:        \"@sap/cds: 5.5.9\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tPackageJSON:    \"{ \\\"name\\\": \\\"my-app\\\",\\\"dependencies\\\": { \\\"@sap/cds\\\": \\\"^5\\\" } }\",\n\t\t\tDisplayMode:    DisplayModeAlways,\n\t\t},\n\t\t{\n\t\t\tCase:           \"8) cds 5.5.0 - file .cdsrc-private.json present\",\n\t\t\tExpectedString: \"5.5.0\",\n\t\t\tVersion:        \"@sap/cds: 5.5.0\\n@sap/cds-compiler: 2.7.0\\n@sap/cds-dk: 4.5.3\",\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"cds\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \".cdsrc.json\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.DisplayMode == \"\" {\n\t\t\ttc.DisplayMode = DisplayModeContext\n\t\t}\n\t\tprops[DisplayMode] = tc.DisplayMode\n\n\t\tenv.On(\"HasFiles\", \"package.json\").Return(len(tc.PackageJSON) != 0)\n\t\tenv.On(\"FileContent\", \"package.json\").Return(tc.PackageJSON)\n\n\t\tcds := &Cds{}\n\t\tcds.Init(props, env)\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = cds.Template()\n\t\t}\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, cds.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, cds), failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/cf.go",
    "content": "package segments\n\ntype Cf struct {\n\tLanguage\n}\n\nfunc (c *Cf) Template() string {\n\treturn languageTemplate\n}\n\nfunc (c *Cf) Enabled() bool {\n\tc.extensions = []string{\"manifest.yml\", \"mta.yaml\"}\n\tc.tooling = map[string]*cmd{\n\t\t\"cf\": {\n\t\t\texecutable: \"cf\",\n\t\t\targs:       []string{\"version\"},\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tc.defaultTooling = []string{\"cf\"}\n\tc.displayMode = c.options.String(DisplayMode, DisplayModeFiles)\n\tc.versionURLTemplate = \"https://github.com/cloudfoundry/cli/releases/tag/v{{ .Full }}\"\n\n\treturn c.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/cf_target.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype CfTarget struct {\n\tBase\n\n\tCfTargetDetails\n}\n\ntype CfTargetDetails struct {\n\tURL   string\n\tUser  string\n\tOrg   string\n\tSpace string\n}\n\nfunc (c *CfTarget) Template() string {\n\treturn \"{{if .Org }}{{ .Org }}{{ end }}{{if .Space }}/{{ .Space }}{{ end }}\"\n}\n\nfunc (c *CfTarget) Enabled() bool {\n\tif !c.env.HasCommand(\"cf\") {\n\t\treturn false\n\t}\n\n\tdisplayMode := c.options.String(DisplayMode, DisplayModeAlways)\n\tif displayMode != DisplayModeFiles {\n\t\treturn c.setCFTargetStatus()\n\t}\n\n\tfiles := c.options.StringArray(options.Files, []string{\"manifest.yml\"})\n\tfor _, file := range files {\n\t\tmanifest, err := c.env.HasParentFilePath(file, false)\n\t\tif err != nil || manifest.IsDir {\n\t\t\tcontinue\n\t\t}\n\n\t\treturn c.setCFTargetStatus()\n\t}\n\n\treturn false\n}\n\nfunc (c *CfTarget) setCFTargetStatus() bool {\n\toutput, err := c.getCFTargetCommandOutput()\n\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tlines := strings.SplitSeq(output, \"\\n\")\n\tfor line := range lines {\n\t\tkey, value, found := strings.Cut(line, \":\")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\tvalue = strings.TrimSpace(value)\n\t\tswitch key {\n\t\tcase \"API endpoint\":\n\t\t\tc.URL = value\n\t\tcase \"user\":\n\t\t\tc.User = value\n\t\tcase \"org\":\n\t\t\tc.Org = value\n\t\tcase \"space\":\n\t\t\tc.Space = value\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (c *CfTarget) getCFTargetCommandOutput() (string, error) {\n\toutput, err := c.env.RunCommand(\"cf\", \"target\")\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif output == \"\" {\n\t\treturn \"\", errors.New(\"cf command output is empty\")\n\t}\n\n\treturn output, nil\n}\n"
  },
  {
    "path": "src/segments/cf_target_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os/exec\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCFTargetSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCommandError   error\n\t\tFileInfo       *runtime.FileInfo\n\t\tCase           string\n\t\tTemplate       string\n\t\tExpectedString string\n\t\tDisplayMode    string\n\t\tTargetOutput   string\n\t}{\n\t\t{\n\t\t\tCase:         \"not logged in to CF account\",\n\t\t\tTargetOutput: `Not logged in`,\n\t\t\tCommandError: &exec.ExitError{},\n\t\t},\n\t\t{\n\t\t\tCase:           \"logged in, default template\",\n\t\t\tExpectedString: \"12345678trial/dev\",\n\t\t\tTargetOutput:   \"API endpoint: https://api.cf.eu10.hana.ondemand.com\\nAPI version: 3.109.0\\nuser: user@some.com\\norg: 12345678trial\\nspace: dev\",\n\t\t},\n\t\t{\n\t\t\tCase: \"no output from command\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"logged in, full template\",\n\t\t\tTemplate:       \"{{.URL}} {{.User}} {{.Org}} {{.Space}}\",\n\t\t\tExpectedString: \"https://api.cf.eu10.hana.ondemand.com user@some.com 12345678trial dev\",\n\t\t\tTargetOutput:   \"API endpoint: https://api.cf.eu10.hana.ondemand.com\\nAPI version: 3.109.0\\nuser: user@some.com\\norg: 12345678trial\\nspace: dev\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"files and no manifest file\",\n\t\t\tDisplayMode:  DisplayModeFiles,\n\t\t\tTargetOutput: \"API endpoint: https://api.cf.eu10.hana.ondemand.com\\nAPI version: 3.109.0\\nuser: user@some.com\\norg: 12345678trial\\nspace: dev\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"files and a manifest file\",\n\t\t\tExpectedString: \"12345678trial/dev\",\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t\tFileInfo:       &runtime.FileInfo{},\n\t\t\tTargetOutput:   \"API endpoint: https://api.cf.eu10.hana.ondemand.com\\nAPI version: 3.109.0\\nuser: user@some.com\\norg: 12345678trial\\nspace: dev\",\n\t\t},\n\t\t{\n\t\t\tCase:        \"files and a manifest directory\",\n\t\t\tDisplayMode: DisplayModeFiles,\n\t\t\tFileInfo: &runtime.FileInfo{\n\t\t\t\tIsDir: true,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tvar env = new(mock.Environment)\n\t\tenv.On(\"HasCommand\", \"cf\").Return(true)\n\t\tenv.On(\"RunCommand\", \"cf\", []string{\"target\"}).Return(tc.TargetOutput, tc.CommandError)\n\t\tenv.On(\"Pwd\", nil).Return(\"/usr/home/dev/my-app\")\n\t\tenv.On(\"Home\", nil).Return(\"/usr/home\")\n\t\tvar err error\n\t\tif tc.FileInfo == nil {\n\t\t\terr = errors.New(\"no such file or directory\")\n\t\t}\n\t\tenv.On(\"HasParentFilePath\", \"manifest.yml\", false).Return(tc.FileInfo, err)\n\n\t\tcfTarget := &CfTarget{}\n\t\tprops := options.Map{\n\t\t\tDisplayMode: tc.DisplayMode,\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = cfTarget.Template()\n\t\t}\n\n\t\tcfTarget.Init(props, env)\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.Equal(t, len(tc.ExpectedString) > 0, cfTarget.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, cfTarget), failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/cf_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCFSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tTemplate       string\n\t\tExpectedString string\n\t\tCfYamlFile     string\n\t\tVersion        string\n\t\tDisplayMode    string\n\t}{\n\t\t{\n\t\t\tCase:           \"1) cf 2.12.1 - file manifest.yml\",\n\t\t\tExpectedString: \"2.12.1\",\n\t\t\tCfYamlFile:     \"manifest.yml\",\n\t\t\tVersion:        `cf.exe version 2.12.1+645c3ce6a.2021-08-16`,\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:           \"2) cf 11.0.0-rc1 - file mta.yaml\",\n\t\t\tTemplate:       \"{{ .Major }}\",\n\t\t\tExpectedString: \"11\",\n\t\t\tCfYamlFile:     \"mta.yaml\",\n\t\t\tVersion:        `cf version 11.0.0-rc1`,\n\t\t\tDisplayMode:    DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:           \"4) cf 11.1.0-rc1 - mode always\",\n\t\t\tTemplate:       \"{{ .Major }}.{{ .Minor }}\",\n\t\t\tExpectedString: \"11.1\",\n\t\t\tVersion:        `cf.exe version 11.1.0-rc1`,\n\t\t\tDisplayMode:    DisplayModeAlways,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"cf\",\n\t\t\tversionParam:  \"version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"manifest.yml\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tprops[DisplayMode] = tc.DisplayMode\n\n\t\tcf := &Cf{}\n\t\tcf.Init(props, env)\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = cf.Template()\n\t\t}\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, cf.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, cf), failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/claude.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\n// Claude segment displays Claude Code session information\ntype Claude struct {\n\tBase\n\tClaudeData\n}\n\n// ClaudeData represents the parsed Claude JSON data\ntype ClaudeData struct {\n\tModel         ClaudeModel         `json:\"model\"`\n\tWorkspace     ClaudeWorkspace     `json:\"workspace\"`\n\tSessionID     string              `json:\"session_id\"`\n\tContextWindow ClaudeContextWindow `json:\"context_window\"`\n\tCost          ClaudeCost          `json:\"cost\"`\n}\n\n// ClaudeModel represents the AI model information\ntype ClaudeModel struct {\n\tID          string `json:\"id\"`\n\tDisplayName string `json:\"display_name\"`\n}\n\n// ClaudeWorkspace represents workspace directory information\ntype ClaudeWorkspace struct {\n\tCurrentDir string `json:\"current_dir\"`\n\tProjectDir string `json:\"project_dir\"`\n}\n\n// ClaudeCost represents cost and duration information\ntype ClaudeCost struct {\n\tTotalCostUSD    float64 `json:\"total_cost_usd\"`\n\tTotalDurationMS int64   `json:\"total_duration_ms\"`\n}\n\n// ClaudeContextWindow represents token usage information\ntype ClaudeContextWindow struct {\n\tUsedPercentage      *int                `json:\"used_percentage\"`\n\tRemainingPercentage *int                `json:\"remaining_percentage\"`\n\tCurrentUsage        *ClaudeCurrentUsage `json:\"current_usage\"`\n\tTotalInputTokens    int                 `json:\"total_input_tokens\"`\n\tTotalOutputTokens   int                 `json:\"total_output_tokens\"`\n\tContextWindowSize   int                 `json:\"context_window_size\"`\n}\n\n// ClaudeCurrentUsage represents current context window usage from the last API call\ntype ClaudeCurrentUsage struct {\n\tInputTokens              int `json:\"input_tokens\"`\n\tOutputTokens             int `json:\"output_tokens\"`\n\tCacheCreationInputTokens int `json:\"cache_creation_input_tokens\"`\n\tCacheReadInputTokens     int `json:\"cache_read_input_tokens\"`\n}\n\nconst (\n\tthousand = 1000.0\n\tmillion  = 1000000.0\n)\n\nfunc (c *Claude) Template() string {\n\treturn \" \\U000f0bc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.Gauge }} \"\n}\n\nfunc (c *Claude) Enabled() bool {\n\tlog.Debug(\"claude segment: checking if enabled\")\n\n\t// Try to get Claude data from session cache\n\tclaudeData, found := cache.Get[ClaudeData](cache.Session, cache.CLAUDECACHE)\n\tif !found {\n\t\tlog.Debug(\"claude segment: no Claude data found in session cache\")\n\t\treturn false\n\t}\n\n\tlog.Debug(\"claude segment: found Claude data in session cache\")\n\tlog.Debugf(\"claude segment: model=%s, session=%s\", claudeData.Model.DisplayName, claudeData.SessionID)\n\n\t// Copy the data to our embedded struct\n\tc.ClaudeData = claudeData\n\n\treturn true\n}\n\n// TokenUsagePercent returns the percentage of context window used.\n// Uses pre-calculated UsedPercentage when available (resets on compact/clear),\n// falls back to calculating from CurrentUsage, then to total tokens for backwards compatibility.\nfunc (c *Claude) TokenUsagePercent() text.Percentage {\n\t// Prefer pre-calculated UsedPercentage - most accurate and resets on compact/clear\n\t// When UsedPercentage is nil (null in JSON), context was reset - return 0\n\tif c.ContextWindow.UsedPercentage != nil {\n\t\tif *c.ContextWindow.UsedPercentage > 100 {\n\t\t\treturn 100\n\t\t}\n\t\treturn text.Percentage(*c.ContextWindow.UsedPercentage)\n\t}\n\n\t// UsedPercentage is nil - check if CurrentUsage is also nil (indicates reset/clear)\n\tif c.ContextWindow.CurrentUsage == nil {\n\t\treturn 0\n\t}\n\n\tif c.ContextWindow.ContextWindowSize <= 0 {\n\t\treturn 0\n\t}\n\n\t// Calculate from CurrentUsage (includes cache tokens for accurate context measurement)\n\tcurrentTokens := c.ContextWindow.CurrentUsage.InputTokens +\n\t\tc.ContextWindow.CurrentUsage.CacheCreationInputTokens +\n\t\tc.ContextWindow.CurrentUsage.CacheReadInputTokens\n\n\t// Fallback to total tokens if CurrentUsage is not provided (backwards compatibility)\n\tif currentTokens <= 0 {\n\t\tcurrentTokens = c.ContextWindow.TotalInputTokens + c.ContextWindow.TotalOutputTokens\n\t}\n\n\tif currentTokens <= 0 {\n\t\treturn 0\n\t}\n\n\t// Use floating-point arithmetic for accurate percentage calculation\n\tpercent := (float64(currentTokens) * 100.0) / float64(c.ContextWindow.ContextWindowSize)\n\n\t// Round to nearest integer and cap at 100\n\troundedPercent := int(percent + 0.5)\n\tif roundedPercent > 100 {\n\t\treturn 100\n\t}\n\n\treturn text.Percentage(roundedPercent)\n}\n\n// FormattedCost returns the cost formatted as a currency string\nfunc (c *Claude) FormattedCost() string {\n\tif c.Cost.TotalCostUSD < 0.01 {\n\t\treturn fmt.Sprintf(\"$%.4f\", c.Cost.TotalCostUSD)\n\t}\n\n\treturn fmt.Sprintf(\"$%.2f\", c.Cost.TotalCostUSD)\n}\n\n// FormattedTokens returns a human-readable string of current context tokens.\n// Uses CurrentUsage (which represents actual context and resets on compact/clear)\n// with fallback to total tokens for backwards compatibility.\nfunc (c *Claude) FormattedTokens() string {\n\tvar currentTokens int\n\n\t// Use CurrentUsage for display - includes cache tokens for accurate context measurement\n\t// When CurrentUsage is nil (context reset), fall back to total tokens\n\tif c.ContextWindow.CurrentUsage != nil {\n\t\tcurrentTokens = c.ContextWindow.CurrentUsage.InputTokens +\n\t\t\tc.ContextWindow.CurrentUsage.CacheCreationInputTokens +\n\t\t\tc.ContextWindow.CurrentUsage.CacheReadInputTokens\n\t}\n\n\t// Fallback to total tokens if CurrentUsage is not provided (backwards compatibility)\n\tif currentTokens <= 0 {\n\t\tcurrentTokens = c.ContextWindow.TotalInputTokens + c.ContextWindow.TotalOutputTokens\n\t}\n\n\tif currentTokens < int(thousand) {\n\t\treturn fmt.Sprintf(\"%d\", currentTokens)\n\t}\n\n\tif currentTokens < int(million) {\n\t\treturn fmt.Sprintf(\"%.1fK\", float64(currentTokens)/thousand)\n\t}\n\n\treturn fmt.Sprintf(\"%.1fM\", float64(currentTokens)/million)\n}\n"
  },
  {
    "path": "src/segments/claude_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestClaudeSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tClaudeData      *ClaudeData\n\t\tExpectedModel   string\n\t\tExpectedSession string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"No cache data\",\n\t\t\tClaudeData:      nil,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase: \"Valid cache data with all fields\",\n\t\t\tClaudeData: &ClaudeData{\n\t\t\t\tSessionID: \"abc123\",\n\t\t\t\tModel: ClaudeModel{\n\t\t\t\t\tID:          \"claude-opus-4-1\",\n\t\t\t\t\tDisplayName: \"Opus\",\n\t\t\t\t},\n\t\t\t\tWorkspace: ClaudeWorkspace{\n\t\t\t\t\tCurrentDir: \"/repo/project\",\n\t\t\t\t\tProjectDir: \"/repo\",\n\t\t\t\t},\n\t\t\t\tCost: ClaudeCost{\n\t\t\t\t\tTotalCostUSD:    0.01,\n\t\t\t\t\tTotalDurationMS: 45000,\n\t\t\t\t},\n\t\t\t\tContextWindow: ClaudeContextWindow{\n\t\t\t\t\tTotalInputTokens:  15234,\n\t\t\t\t\tTotalOutputTokens: 4521,\n\t\t\t\t\tContextWindowSize: 200000,\n\t\t\t\t\tCurrentUsage: &ClaudeCurrentUsage{\n\t\t\t\t\t\tInputTokens:  8500,\n\t\t\t\t\t\tOutputTokens: 1200,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedModel:   \"Opus\",\n\t\t\tExpectedSession: \"abc123\",\n\t\t},\n\t\t{\n\t\t\tCase: \"Valid cache data with partial fields\",\n\t\t\tClaudeData: &ClaudeData{\n\t\t\t\tSessionID: \"xyz789\",\n\t\t\t\tModel: ClaudeModel{\n\t\t\t\t\tID:          \"claude-sonnet-3-5\",\n\t\t\t\t\tDisplayName: \"Sonnet 3.5\",\n\t\t\t\t},\n\t\t\t\tContextWindow: ClaudeContextWindow{\n\t\t\t\t\tTotalInputTokens:  1000,\n\t\t\t\t\tTotalOutputTokens: 500,\n\t\t\t\t\tContextWindowSize: 100000,\n\t\t\t\t},\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedModel:   \"Sonnet 3.5\",\n\t\t\tExpectedSession: \"xyz789\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\t// Setup cache for test\n\t\tif tc.ClaudeData != nil {\n\t\t\tcache.Set(cache.Session, cache.CLAUDECACHE, *tc.ClaudeData, cache.INFINITE)\n\t\t} else {\n\t\t\tcache.Delete(cache.Session, cache.CLAUDECACHE)\n\t\t}\n\n\t\tenv := new(mock.Environment)\n\t\tclaude := &Claude{\n\t\t\tBase: Base{\n\t\t\t\tenv:     env,\n\t\t\t\toptions: options.Map{},\n\t\t\t},\n\t\t}\n\n\t\tenabled := claude.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedModel, claude.Model.DisplayName, tc.Case)\n\t\t\tassert.Equal(t, tc.ExpectedSession, claude.SessionID, tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestClaudeTokenUsagePercent(t *testing.T) {\n\tcases := []struct {\n\t\tUsedPercentage           *int\n\t\tCase                     string\n\t\tInputTokens              int\n\t\tOutputTokens             int\n\t\tCurrentInput             int\n\t\tCacheCreationInputTokens int\n\t\tCacheReadInputTokens     int\n\t\tContextWindow            int\n\t\tExpectedPercent          text.Percentage\n\t\tHasCurrentUsage          bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Uses UsedPercentage when available\",\n\t\t\tUsedPercentage:  new(42),\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 42,\n\t\t},\n\t\t{\n\t\t\tCase:            \"UsedPercentage capped at 100\",\n\t\t\tUsedPercentage:  new(150),\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 100,\n\t\t},\n\t\t{\n\t\t\tCase:            \"UsedPercentage zero is valid\",\n\t\t\tUsedPercentage:  new(0),\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 0,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Context reset - both UsedPercentage and CurrentUsage nil\",\n\t\t\tUsedPercentage:  nil,\n\t\t\tHasCurrentUsage: false,\n\t\t\tInputTokens:     50000, // High cumulative total - should be ignored\n\t\t\tOutputTokens:    50000,\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 0, // Should return 0 after reset, not fallback to total\n\t\t},\n\t\t{\n\t\t\tCase:            \"Zero context window (no UsedPercentage)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     1000,\n\t\t\tOutputTokens:    500,\n\t\t\tContextWindow:   0,\n\t\t\tExpectedPercent: 0,\n\t\t},\n\t\t{\n\t\t\tCase:            \"10% usage (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     8000,\n\t\t\tOutputTokens:    2000,\n\t\t\tContextWindow:   100000,\n\t\t\tExpectedPercent: 10,\n\t\t},\n\t\t{\n\t\t\tCase:            \"50% usage (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     50000,\n\t\t\tOutputTokens:    50000,\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 50,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Over 100% usage (capped)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     100000,\n\t\t\tOutputTokens:    50000,\n\t\t\tContextWindow:   100000,\n\t\t\tExpectedPercent: 100,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Uses CurrentUsage input tokens\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     100000, // High cumulative total\n\t\t\tOutputTokens:    50000,\n\t\t\tCurrentInput:    20000, // Current context input\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 10, // Should use current input (20000/200000 = 10%)\n\t\t},\n\t\t{\n\t\t\tCase:                     \"Uses CurrentUsage with cache tokens\",\n\t\t\tHasCurrentUsage:          true,\n\t\t\tInputTokens:              100000, // High cumulative total\n\t\t\tOutputTokens:             50000,\n\t\t\tCurrentInput:             10000,\n\t\t\tCacheCreationInputTokens: 5000,\n\t\t\tCacheReadInputTokens:     5000,\n\t\t\tContextWindow:            200000,\n\t\t\tExpectedPercent:          10, // (10000+5000+5000)/200000 = 10%\n\t\t},\n\t\t{\n\t\t\tCase:            \"Uses CurrentUsage after compact (low current, high total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     100000, // High cumulative total\n\t\t\tOutputTokens:    50000,\n\t\t\tCurrentInput:    6000, // Low current context (after compact)\n\t\t\tContextWindow:   200000,\n\t\t\tExpectedPercent: 3, // Should use current (6000/200000 = 3%)\n\t\t},\n\t\t{\n\t\t\tCase:            \"Fallback to total when CurrentUsage is zero\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     20000,\n\t\t\tOutputTokens:    10000,\n\t\t\tCurrentInput:    0,\n\t\t\tContextWindow:   100000,\n\t\t\tExpectedPercent: 30, // Should fallback to total (30000/100000 = 30%)\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tclaude := &Claude{}\n\t\tclaude.ContextWindow.TotalInputTokens = tc.InputTokens\n\t\tclaude.ContextWindow.TotalOutputTokens = tc.OutputTokens\n\t\tif tc.HasCurrentUsage {\n\t\t\tclaude.ContextWindow.CurrentUsage = &ClaudeCurrentUsage{\n\t\t\t\tInputTokens:              tc.CurrentInput,\n\t\t\t\tCacheCreationInputTokens: tc.CacheCreationInputTokens,\n\t\t\t\tCacheReadInputTokens:     tc.CacheReadInputTokens,\n\t\t\t}\n\t\t}\n\t\tclaude.ContextWindow.UsedPercentage = tc.UsedPercentage\n\t\tclaude.ContextWindow.ContextWindowSize = tc.ContextWindow\n\n\t\tpercent := claude.TokenUsagePercent()\n\t\tassert.Equal(t, tc.ExpectedPercent, percent, tc.Case)\n\t}\n}\n\nfunc TestClaudeFormattedCost(t *testing.T) {\n\tcases := []struct {\n\t\tCase         string\n\t\tExpectedCost string\n\t\tCostUSD      float64\n\t}{\n\t\t{\n\t\t\tCase:         \"Very small cost\",\n\t\t\tCostUSD:      0.0012,\n\t\t\tExpectedCost: \"$0.0012\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"Small cost\",\n\t\t\tCostUSD:      0.0099,\n\t\t\tExpectedCost: \"$0.0099\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"Regular cost\",\n\t\t\tCostUSD:      0.15,\n\t\t\tExpectedCost: \"$0.15\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"Large cost\",\n\t\t\tCostUSD:      12.34,\n\t\t\tExpectedCost: \"$12.34\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tclaude := &Claude{}\n\t\tclaude.Cost.TotalCostUSD = tc.CostUSD\n\n\t\tformatted := claude.FormattedCost()\n\t\tassert.Equal(t, tc.ExpectedCost, formatted, tc.Case)\n\t}\n}\n\nfunc TestClaudeFormattedTokens(t *testing.T) {\n\tcases := []struct {\n\t\tCase                     string\n\t\tExpectedFormat           string\n\t\tInputTokens              int\n\t\tOutputTokens             int\n\t\tCurrentInput             int\n\t\tCacheCreationInputTokens int\n\t\tCacheReadInputTokens     int\n\t\tHasCurrentUsage          bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Small token count (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     300,\n\t\t\tOutputTokens:    200,\n\t\t\tExpectedFormat:  \"500\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Thousands (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     8500,\n\t\t\tOutputTokens:    1500,\n\t\t\tExpectedFormat:  \"10.0K\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Tens of thousands (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     50000,\n\t\t\tOutputTokens:    25000,\n\t\t\tExpectedFormat:  \"75.0K\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Millions (fallback to total)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     1500000,\n\t\t\tOutputTokens:    500000,\n\t\t\tExpectedFormat:  \"2.0M\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Uses CurrentUsage input tokens\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     100000, // High cumulative total\n\t\t\tOutputTokens:    50000,\n\t\t\tCurrentInput:    10000, // Current context input\n\t\t\tExpectedFormat:  \"10.0K\",\n\t\t},\n\t\t{\n\t\t\tCase:                     \"Uses CurrentUsage with cache tokens\",\n\t\t\tHasCurrentUsage:          true,\n\t\t\tInputTokens:              100000, // High cumulative total\n\t\t\tOutputTokens:             50000,\n\t\t\tCurrentInput:             5000,\n\t\t\tCacheCreationInputTokens: 2500,\n\t\t\tCacheReadInputTokens:     2500,\n\t\t\tExpectedFormat:           \"10.0K\", // 5000+2500+2500 = 10000\n\t\t},\n\t\t{\n\t\t\tCase:            \"Uses CurrentUsage after compact (low current)\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     500000, // High cumulative total\n\t\t\tOutputTokens:    200000,\n\t\t\tCurrentInput:    500, // Low current context (after compact)\n\t\t\tExpectedFormat:  \"500\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Fallback to total when CurrentUsage is zero\",\n\t\t\tHasCurrentUsage: true,\n\t\t\tInputTokens:     50000,\n\t\t\tOutputTokens:    25000,\n\t\t\tCurrentInput:    0,\n\t\t\tExpectedFormat:  \"75.0K\", // Should fallback to total\n\t\t},\n\t\t{\n\t\t\tCase:            \"Nil CurrentUsage falls back to total\",\n\t\t\tHasCurrentUsage: false,\n\t\t\tInputTokens:     50000,\n\t\t\tOutputTokens:    25000,\n\t\t\tExpectedFormat:  \"75.0K\", // Should fallback to total\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tclaude := &Claude{}\n\t\tclaude.ContextWindow.TotalInputTokens = tc.InputTokens\n\t\tclaude.ContextWindow.TotalOutputTokens = tc.OutputTokens\n\t\tif tc.HasCurrentUsage {\n\t\t\tclaude.ContextWindow.CurrentUsage = &ClaudeCurrentUsage{\n\t\t\t\tInputTokens:              tc.CurrentInput,\n\t\t\t\tCacheCreationInputTokens: tc.CacheCreationInputTokens,\n\t\t\t\tCacheReadInputTokens:     tc.CacheReadInputTokens,\n\t\t\t}\n\t\t}\n\n\t\tformatted := claude.FormattedTokens()\n\t\tassert.Equal(t, tc.ExpectedFormat, formatted, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/clojure.go",
    "content": "package segments\n\ntype Clojure struct {\n\tLanguage\n}\n\nfunc (c *Clojure) Template() string {\n\treturn languageTemplate\n}\n\nfunc (c *Clojure) Enabled() bool {\n\tc.init()\n\treturn c.Language.Enabled()\n}\n\nfunc (c *Clojure) init() {\n\toptions := c.options.StringArray(Tooling, []string{})\n\tif len(options) == 0 {\n\t\tc.defaultTooling = []string{\"clojure\", \"lein\"}\n\t}\n\n\tc.extensions = []string{\n\t\t\"project.clj\",\n\t\t\"deps.edn\",\n\t\t\"build.boot\",\n\t\t\"bb.edn\",\n\t\t\"*.clj\",\n\t\t\"*.cljc\",\n\t\t\"*.cljs\",\n\t}\n\n\tc.tooling = map[string]*cmd{\n\t\t\"clojure\": {\n\t\t\texecutable: \"clojure\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Clojure CLI version (?P<version>(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)\\.(?P<patch>[0-9]+)(?:\\.(?P<build>[0-9]+))?)`,\n\t\t},\n\t\t\"lein\": {\n\t\t\texecutable: \"lein\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Leiningen (?P<version>(?P<major>[0-9]+)\\.(?P<minor>[0-9]+)\\.(?P<patch>[0-9]+))`,\n\t\t},\n\t}\n}\n"
  },
  {
    "path": "src/segments/clojure_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestClojure(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t\tCmd            string\n\t}{\n\t\t{\n\t\t\tCase:           \"Clojure CLI 1.11.1.1113\",\n\t\t\tExpectedString: \"1.11.1.1113\",\n\t\t\tVersion:        \"Clojure CLI version 1.11.1.1113\",\n\t\t\tCmd:            \"clojure\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Leiningen 2.9.8\",\n\t\t\tExpectedString: \"2.9.8\",\n\t\t\tVersion:        \"Leiningen 2.9.8 on Java 11.0.11 OpenJDK 64-Bit Server VM\",\n\t\t\tCmd:            \"lein\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           tc.Cmd,\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.clj\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tprops[LanguageExtensions] = []string{params.extension}\n\t\tif tc.Cmd != \"clojure\" {\n\t\t\tenv.On(\"HasCommand\", \"clojure\").Return(false)\n\t\t}\n\t\tc := &Clojure{}\n\t\tc.Init(props, env)\n\t\tassert.True(t, c.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, c.Template(), c), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/cmake.go",
    "content": "package segments\n\ntype Cmake struct {\n\tLanguage\n}\n\nfunc (c *Cmake) Template() string {\n\treturn languageTemplate\n}\n\nfunc (c *Cmake) Enabled() bool {\n\tc.extensions = []string{\"*.cmake\", \"CMakeLists.txt\"}\n\tc.tooling = map[string]*cmd{\n\t\t\"cmake\": {\n\t\t\texecutable: \"cmake\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `cmake version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tc.defaultTooling = []string{\"cmake\"}\n\tc.versionURLTemplate = \"https://cmake.org/cmake/help/v{{ .Major }}.{{ .Minor }}\"\n\n\treturn c.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/cmake_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCmake(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Cmake 3.23.2\", ExpectedString: \"3.23.2\", Version: \"cmake version 3.23.2\"},\n\t\t{Case: \"Cmake 2.3.13\", ExpectedString: \"2.3.12\", Version: \"cmake version 2.3.12\"},\n\t\t{Case: \"\", ExpectedString: \"err parsing info from cmake with\", Version: \"\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"cmake\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.cmake\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tc := &Cmake{}\n\t\tc.Init(props, env)\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, c.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, c.Template(), c), failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/connection.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Connection struct {\n\tBase\n\n\truntime.Connection\n}\n\nconst (\n\tType options.Option = \"type\"\n)\n\nfunc (c *Connection) Template() string {\n\treturn \" {{ if eq .Type \\\"wifi\\\"}}\\uf1eb{{ else if eq .Type \\\"ethernet\\\"}}\\ueba9{{ end }} \"\n}\n\nfunc (c *Connection) Enabled() bool {\n\ttypes := c.options.String(Type, \"wifi|ethernet\")\n\tconnectionTypes := strings.SplitSeq(types, \"|\")\n\tfor connectionType := range connectionTypes {\n\t\tnetwork, err := c.env.Connection(runtime.ConnectionType(connectionType))\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tc.Connection = *network\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/connection_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestConnection(t *testing.T) {\n\ttype connectionResponse struct {\n\t\tConnection *runtime.Connection\n\t\tError      error\n\t}\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tConnectionType  string\n\t\tConnections     []*connectionResponse\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"WiFi only, enabled\",\n\t\t\tExpectedString:  \"\\uf1eb\",\n\t\t\tExpectedEnabled: true,\n\t\t\tConnectionType:  \"wifi\",\n\t\t\tConnections: []*connectionResponse{\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tName: \"WiFi\",\n\t\t\t\t\t\tType: \"wifi\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"WiFi only, disabled\",\n\t\t\tConnectionType: \"wifi\",\n\t\t\tConnections: []*connectionResponse{\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tType: runtime.WIFI,\n\t\t\t\t\t},\n\t\t\t\t\tError: fmt.Errorf(\"no connection\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:            \"WiFi and Ethernet, enabled\",\n\t\t\tConnectionType:  \"wifi|ethernet\",\n\t\t\tExpectedString:  \"\\ueba9\",\n\t\t\tExpectedEnabled: true,\n\t\t\tConnections: []*connectionResponse{\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tType: runtime.WIFI,\n\t\t\t\t\t},\n\t\t\t\t\tError: fmt.Errorf(\"no connection\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tType: runtime.ETHERNET,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"WiFi and Ethernet, disabled\",\n\t\t\tConnectionType: \"wifi|ethernet\",\n\t\t\tConnections: []*connectionResponse{\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tType: runtime.WIFI,\n\t\t\t\t\t},\n\t\t\t\t\tError: fmt.Errorf(\"no connection\"),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tConnection: &runtime.Connection{\n\t\t\t\t\t\tType: runtime.ETHERNET,\n\t\t\t\t\t},\n\t\t\t\t\tError: fmt.Errorf(\"no connection\"),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tfor _, con := range tc.Connections {\n\t\t\tenv.On(\"Connection\", con.Connection.Type).Return(con.Connection, con.Error)\n\t\t}\n\n\t\tprops := &options.Map{\n\t\t\tType: tc.ConnectionType,\n\t\t}\n\n\t\tc := &Connection{}\n\t\tc.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, c.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, c.Template(), c), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/copilot.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/auth\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\n// CopilotUsage represents usage statistics for a specific quota type.\ntype CopilotUsage struct {\n\tUsed      int             `json:\"used\"`\n\tLimit     int             `json:\"limit\"`\n\tPercent   text.Percentage `json:\"percent\"`\n\tRemaining text.Percentage `json:\"remaining\"`\n\tUnlimited bool            `json:\"unlimited\"`\n}\n\n// Copilot displays GitHub Copilot usage statistics.\ntype Copilot struct {\n\tBase\n\tBillingCycleEnd string       `json:\"billing_cycle_end\"`\n\tPremium         CopilotUsage `json:\"premium\"`\n\tInline          CopilotUsage `json:\"inline\"`\n\tChat            CopilotUsage `json:\"chat\"`\n}\n\nconst (\n\tcopilotAPIURL = \"https://api.github.com/copilot_internal/user\"\n)\n\n// copilotQuotaSnapshot represents a single quota type.\ntype copilotQuotaSnapshot struct {\n\tEntitlement int  `json:\"entitlement\"`\n\tRemaining   int  `json:\"remaining\"`\n\tUnlimited   bool `json:\"unlimited\"`\n}\n\n// copilotQuotaSnapshots represents the quota snapshots structure.\ntype copilotQuotaSnapshots struct {\n\tPremiumInteractions copilotQuotaSnapshot `json:\"premium_interactions\"`\n\tCompletions         copilotQuotaSnapshot `json:\"completions\"`\n\tChat                copilotQuotaSnapshot `json:\"chat\"`\n}\n\n// copilotAPIResponse represents the API response structure.\ntype copilotAPIResponse struct {\n\tQuotaSnapshots    *copilotQuotaSnapshots `json:\"quota_snapshots\"`\n\tQuotaResetDate    string                 `json:\"quota_reset_date\"`\n\tQuotaResetDateUTC string                 `json:\"quota_reset_date_utc\"`\n}\n\nfunc (c *Copilot) Template() string {\n\treturn \" \\uec1e {{ .Premium.Percent.Gauge }} \"\n}\n\nfunc (c *Copilot) Enabled() bool {\n\terr := c.setStatus()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (c *Copilot) getAccessToken() string {\n\t// Check cache from `oh-my-posh auth copilot`\n\tif cachedToken, OK := cache.Get[string](cache.Device, auth.CopilotTokenKey); OK && len(cachedToken) != 0 {\n\t\treturn cachedToken\n\t}\n\n\treturn \"\"\n}\n\nfunc (c *Copilot) getResult() (*copilotAPIResponse, error) {\n\taccessToken := c.getAccessToken()\n\tif len(accessToken) == 0 {\n\t\treturn nil, &noAccessTokenError{}\n\t}\n\n\tlog.Debug(\"found access token\")\n\n\thttpTimeout := c.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\taddAuthHeader := func(request *http.Request) {\n\t\trequest.Header.Set(\"Authorization\", \"Bearer \"+accessToken)\n\t\trequest.Header.Set(\"User-Agent\", \"GitHub-Copilot-Usage-Tray\")\n\t\trequest.Header.Set(\"Accept\", \"application/json\")\n\t\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\tbody, err := c.env.HTTPRequest(copilotAPIURL, nil, httpTimeout, addAuthHeader)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\tlog.Debug(\"executed HTTP request successfully\")\n\n\tresponse := new(copilotAPIResponse)\n\terr = json.Unmarshal(body, &response)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn response, nil\n}\n\nfunc (c *Copilot) setStatus() error {\n\tresponse, err := c.getResult()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Extract quota data from response - try different paths\n\tquotaSnapshots := c.extractQuotaSnapshots(response)\n\tif quotaSnapshots == nil {\n\t\treturn &noQuotaDataError{}\n\t}\n\n\t// Calculate premium usage\n\tc.Premium = c.calculateUsage(quotaSnapshots.PremiumInteractions)\n\n\t// Calculate inline usage (completions)\n\tc.Inline = c.calculateUsage(quotaSnapshots.Completions)\n\n\t// Calculate chat usage\n\tc.Chat = c.calculateUsage(quotaSnapshots.Chat)\n\n\t// Set billing cycle end date\n\tc.BillingCycleEnd = response.QuotaResetDate\n\tif c.BillingCycleEnd == \"\" {\n\t\tc.BillingCycleEnd = response.QuotaResetDateUTC\n\t}\n\n\treturn nil\n}\n\nfunc (c *Copilot) extractQuotaSnapshots(response *copilotAPIResponse) *copilotQuotaSnapshots {\n\tif response == nil {\n\t\treturn nil\n\t}\n\n\t// Use root-level quota_snapshots\n\tif response.QuotaSnapshots != nil {\n\t\treturn response.QuotaSnapshots\n\t}\n\n\treturn nil\n}\n\nfunc (c *Copilot) calculateUsage(snapshot copilotQuotaSnapshot) CopilotUsage {\n\tif snapshot.Unlimited {\n\t\treturn CopilotUsage{\n\t\t\tUsed:      0,\n\t\t\tLimit:     0,\n\t\t\tPercent:   text.Percentage(0),\n\t\t\tRemaining: text.Percentage(100),\n\t\t\tUnlimited: true,\n\t\t}\n\t}\n\n\tused := max(snapshot.Entitlement-snapshot.Remaining, 0)\n\tpercent := c.calculatePercent(used, snapshot.Entitlement)\n\tremainingPercent := 100 - percent\n\n\treturn CopilotUsage{\n\t\tUsed:      used,\n\t\tLimit:     snapshot.Entitlement,\n\t\tPercent:   text.Percentage(percent),\n\t\tRemaining: text.Percentage(remainingPercent),\n\t\tUnlimited: false,\n\t}\n}\n\nfunc (c *Copilot) calculatePercent(used, limit int) int {\n\tif limit <= 0 {\n\t\treturn 0\n\t}\n\n\tpercent := (used * 100) / limit\n\tif percent > 100 {\n\t\treturn 100\n\t}\n\n\treturn percent\n}\n\n// Custom error types for better error handling\n\ntype noQuotaDataError struct{}\n\nfunc (e *noQuotaDataError) Error() string {\n\treturn \"no quota data in response\"\n}\n\ntype noAccessTokenError struct{}\n\nfunc (e *noAccessTokenError) Error() string {\n\treturn \"no access token available, use 'oh-my-posh auth copilot' to authenticate\"\n}\n"
  },
  {
    "path": "src/segments/copilot_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/auth\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tcopilotTestURL = \"https://api.github.com/copilot_internal/user\"\n)\n\nfunc TestCopilotSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tJSONResponse    string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tHasToken        bool\n\t\tExpectedEnabled bool\n\t\tHasError        bool\n\t}{\n\t\t{\n\t\t\tCase: \"Valid response with usage data\",\n\t\t\tJSONResponse: `{\n\t\t\t\t\"quota_snapshots\": {\n\t\t\t\t\t\"premium_interactions\": {\n\t\t\t\t\t\t\"entitlement\": 50,\n\t\t\t\t\t\t\"remaining\": 35,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"completions\": {\n\t\t\t\t\t\t\"entitlement\": 2000,\n\t\t\t\t\t\t\"remaining\": 1500,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"chat\": {\n\t\t\t\t\t\t\"entitlement\": 100,\n\t\t\t\t\t\t\"remaining\": 80,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"quota_reset_date\": \"2025-02-01T00:00:00Z\"\n\t\t\t}`,\n\t\t\tTemplate:        \" \\uec1e {{ .Premium.Used }}/{{ .Premium.Limit }} | {{ .Inline.Used }}/{{ .Inline.Limit }} | {{ .Chat.Used }}/{{ .Chat.Limit }} \",\n\t\t\tExpectedString:  \"\\uec1e 15/50 | 500/2000 | 20/100\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Full premium usage\",\n\t\t\tJSONResponse: `{\n\t\t\t\t\"quota_snapshots\": {\n\t\t\t\t\t\"premium_interactions\": {\n\t\t\t\t\t\t\"entitlement\": 50,\n\t\t\t\t\t\t\"remaining\": 0,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"completions\": {\n\t\t\t\t\t\t\"entitlement\": 2000,\n\t\t\t\t\t\t\"remaining\": 0,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"chat\": {\n\t\t\t\t\t\t\"entitlement\": 100,\n\t\t\t\t\t\t\"remaining\": 0,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"quota_reset_date\": \"2025-02-01T00:00:00Z\"\n\t\t\t}`,\n\t\t\tTemplate:        \" \\uec1e {{ .Premium.Used }}/{{ .Premium.Limit }} | {{ .Inline.Used }}/{{ .Inline.Limit }} | {{ .Chat.Used }}/{{ .Chat.Limit }} \",\n\t\t\tExpectedString:  \"\\uec1e 50/50 | 2000/2000 | 100/100\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase: \"No usage\",\n\t\t\tJSONResponse: `{\n\t\t\t\t\"quota_snapshots\": {\n\t\t\t\t\t\"premium_interactions\": {\n\t\t\t\t\t\t\"entitlement\": 50,\n\t\t\t\t\t\t\"remaining\": 50,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"completions\": {\n\t\t\t\t\t\t\"entitlement\": 2000,\n\t\t\t\t\t\t\"remaining\": 2000,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"chat\": {\n\t\t\t\t\t\t\"entitlement\": 0,\n\t\t\t\t\t\t\"remaining\": 0,\n\t\t\t\t\t\t\"unlimited\": true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"quota_reset_date\": \"2025-02-01T00:00:00Z\"\n\t\t\t}`,\n\t\t\tTemplate:        \" \\uec1e {{ .Premium.Used }}/{{ .Premium.Limit }} | {{ .Inline.Used }}/{{ .Inline.Limit }} | {{ .Chat.Used }}/{{ .Chat.Limit }} \",\n\t\t\tExpectedString:  \"\\uec1e 0/50 | 0/2000 | 0/0\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Custom template with percentages\",\n\t\t\tJSONResponse: `{\n\t\t\t\t\"quota_snapshots\": {\n\t\t\t\t\t\"premium_interactions\": {\n\t\t\t\t\t\t\"entitlement\": 100,\n\t\t\t\t\t\t\"remaining\": 50,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"completions\": {\n\t\t\t\t\t\t\"entitlement\": 1000,\n\t\t\t\t\t\t\"remaining\": 750,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t},\n\t\t\t\t\t\"chat\": {\n\t\t\t\t\t\t\"entitlement\": 200,\n\t\t\t\t\t\t\"remaining\": 100,\n\t\t\t\t\t\t\"unlimited\": false\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"quota_reset_date\": \"2025-02-01T00:00:00Z\"\n\t\t\t}`,\n\t\t\tTemplate:        \" {{ .Premium.Percent }}% | {{ .Inline.Percent }}% | {{ .Chat.Percent }}% \",\n\t\t\tExpectedString:  \"50% | 25% | 50%\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"No access token\",\n\t\t\tExpectedEnabled: false,\n\t\t\tHasError:        false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"API error\",\n\t\t\tHasError:        true,\n\t\t\tExpectedEnabled: false,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid JSON response\",\n\t\t\tJSONResponse:    \"invalid json\",\n\t\t\tExpectedEnabled: false,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty quota data\",\n\t\t\tJSONResponse:    `{}`,\n\t\t\tExpectedEnabled: false,\n\t\t\tHasToken:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Null quota_snapshots\",\n\t\t\tJSONResponse:    `{\"quota_snapshots\": null}`,\n\t\t\tExpectedEnabled: false,\n\t\t\tHasToken:        true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tenv := &mock.Environment{}\n\t\t\tprops := options.Map{}\n\n\t\t\t// Setup cached token mock\n\t\t\tif tc.HasToken {\n\t\t\t\tcache.Set(cache.Device, auth.CopilotTokenKey, \"ghp_test_token\", cache.INFINITE)\n\t\t\t} else {\n\t\t\t\tcache.Delete(cache.Device, auth.CopilotTokenKey)\n\t\t\t}\n\n\t\t\t// Setup HTTP request mock\n\t\t\tvar httpErr error\n\t\t\tif tc.HasError {\n\t\t\t\thttpErr = errors.New(\"request failed\")\n\t\t\t}\n\n\t\t\tif tc.HasToken {\n\t\t\t\tenv.On(\"HTTPRequest\", copilotTestURL).Return([]byte(tc.JSONResponse), httpErr)\n\t\t\t}\n\n\t\t\tc := &Copilot{}\n\t\t\tc.Init(props, env)\n\n\t\t\tenabled := c.Enabled()\n\t\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\t\tif !enabled {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttemplate := tc.Template\n\t\t\tif template == \"\" {\n\t\t\t\ttemplate = c.Template()\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, template, c), tc.Case)\n\t\t})\n\t}\n}\n\nfunc TestCopilotPercentageCalculation(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tUsed            int\n\t\tLimit           int\n\t\tExpectedPercent int\n\t}{\n\t\t{\n\t\t\tCase:            \"50 percent\",\n\t\t\tUsed:            50,\n\t\t\tLimit:           100,\n\t\t\tExpectedPercent: 50,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Zero limit\",\n\t\t\tUsed:            10,\n\t\t\tLimit:           0,\n\t\t\tExpectedPercent: 0,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Negative limit\",\n\t\t\tUsed:            10,\n\t\t\tLimit:           -5,\n\t\t\tExpectedPercent: 0,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Over 100 percent caps at 100\",\n\t\t\tUsed:            150,\n\t\t\tLimit:           100,\n\t\t\tExpectedPercent: 100,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Zero used\",\n\t\t\tUsed:            0,\n\t\t\tLimit:           100,\n\t\t\tExpectedPercent: 0,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Full usage\",\n\t\t\tUsed:            100,\n\t\t\tLimit:           100,\n\t\t\tExpectedPercent: 100,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tc := &Copilot{}\n\t\t\tresult := c.calculatePercent(tc.Used, tc.Limit)\n\t\t\tassert.Equal(t, tc.ExpectedPercent, result, tc.Case)\n\t\t})\n\t}\n}\n\nfunc TestCopilotRemainingPercentage(t *testing.T) {\n\tenv := &mock.Environment{}\n\tprops := options.Map{}\n\n\tjsonResponse := `{\n\t\t\"quota_snapshots\": {\n\t\t\t\"premium_interactions\": {\n\t\t\t\t\"entitlement\": 100,\n\t\t\t\t\"remaining\": 75,\n\t\t\t\t\"unlimited\": false\n\t\t\t},\n\t\t\t\"completions\": {\n\t\t\t\t\"entitlement\": 1000,\n\t\t\t\t\"remaining\": 600,\n\t\t\t\t\"unlimited\": false\n\t\t\t},\n\t\t\t\"chat\": {\n\t\t\t\t\"entitlement\": 200,\n\t\t\t\t\"remaining\": 0,\n\t\t\t\t\"unlimited\": false\n\t\t\t}\n\t\t},\n\t\t\"quota_reset_date\": \"2025-02-15T00:00:00Z\"\n\t}`\n\n\tcache.Set(cache.Device, auth.CopilotTokenKey, \"ghp_test_token\", cache.INFINITE)\n\tenv.On(\"HTTPRequest\", copilotTestURL).Return([]byte(jsonResponse), nil)\n\n\tc := &Copilot{}\n\tc.Init(props, env)\n\n\tenabled := c.Enabled()\n\tassert.True(t, enabled)\n\n\t// Test Premium: 100 entitlement - 75 remaining = 25 used (25% used, 75% remaining)\n\tassert.Equal(t, text.Percentage(25), c.Premium.Percent)\n\tassert.Equal(t, text.Percentage(75), c.Premium.Remaining)\n\n\t// Test Inline: 1000 entitlement - 600 remaining = 400 used (40% used, 60% remaining)\n\tassert.Equal(t, text.Percentage(40), c.Inline.Percent)\n\tassert.Equal(t, text.Percentage(60), c.Inline.Remaining)\n\n\t// Test Chat: 200 entitlement - 0 remaining = 200 used (100% used, 0% remaining)\n\tassert.Equal(t, text.Percentage(100), c.Chat.Percent)\n\tassert.Equal(t, text.Percentage(0), c.Chat.Remaining)\n}\n\nfunc TestCopilotBillingCycleEnd(t *testing.T) {\n\tenv := &mock.Environment{}\n\tprops := options.Map{}\n\n\tjsonResponse := `{\n\t\t\"quota_snapshots\": {\n\t\t\t\"premium_interactions\": {\n\t\t\t\t\"entitlement\": 50,\n\t\t\t\t\"remaining\": 35,\n\t\t\t\t\"unlimited\": false\n\t\t\t},\n\t\t\t\"completions\": {\n\t\t\t\t\"entitlement\": 2000,\n\t\t\t\t\"remaining\": 1500,\n\t\t\t\t\"unlimited\": false\n\t\t\t},\n\t\t\t\"chat\": {\n\t\t\t\t\"entitlement\": 100,\n\t\t\t\t\"remaining\": 80,\n\t\t\t\t\"unlimited\": false\n\t\t\t}\n\t\t},\n\t\t\"quota_reset_date\": \"2025-02-15T00:00:00Z\"\n\t}`\n\n\tcache.Set(cache.Device, auth.CopilotTokenKey, \"ghp_test_token\", cache.INFINITE)\n\tenv.On(\"HTTPRequest\", copilotTestURL).Return([]byte(jsonResponse), nil)\n\n\tc := &Copilot{}\n\tc.Init(props, env)\n\n\tenabled := c.Enabled()\n\tassert.True(t, enabled)\n\tassert.Equal(t, \"2025-02-15T00:00:00Z\", c.BillingCycleEnd)\n}\n"
  },
  {
    "path": "src/segments/crystal.go",
    "content": "package segments\n\ntype Crystal struct {\n\tLanguage\n}\n\nfunc (c *Crystal) Template() string {\n\treturn languageTemplate\n}\n\nfunc (c *Crystal) Enabled() bool {\n\tc.extensions = []string{\"*.cr\", \"shard.yml\"}\n\tc.tooling = map[string]*cmd{\n\t\t\"crystal\": {\n\t\t\texecutable: \"crystal\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Crystal (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tc.defaultTooling = []string{\"crystal\"}\n\tc.versionURLTemplate = \"https://github.com/crystal-lang/crystal/releases/tag/{{ .Full }}\"\n\n\treturn c.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/crystal_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCrystal(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Crystal 1.0.0\", ExpectedString: \"1.0.0\", Version: \"Crystal 1.0.0 (2021-03-22)\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"crystal\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.cr\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tc := &Crystal{}\n\t\tc.Init(props, env)\n\t\tassert.True(t, c.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, c.Template(), c), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/dart.go",
    "content": "package segments\n\nvar (\n\tdartExtensions = []string{\"*.dart\", \"pubspec.yaml\", \"pubspec.yml\", \"pubspec.lock\"}\n\tdartFolders    = []string{\".dart_tool\"}\n)\n\ntype Dart struct {\n\tLanguage\n}\n\nfunc (d *Dart) Template() string {\n\treturn languageTemplate\n}\n\nfunc (d *Dart) Enabled() bool {\n\td.extensions = dartExtensions\n\td.folders = dartFolders\n\td.tooling = map[string]*cmd{\n\t\t\"fvm\": {\n\t\t\texecutable: \"fvm\",\n\t\t\targs:       []string{\"dart\", \"--version\"},\n\t\t\tregex:      `Dart SDK version: (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t\t\"dart\": {\n\t\t\texecutable: \"dart\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Dart SDK version: (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\td.defaultTooling = []string{\"fvm\", \"dart\"}\n\td.versionURLTemplate = \"https://dart.dev/guides/language/evolution#dart-{{ .Major }}{{ .Minor }}\"\n\n\treturn d.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/dart_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDart(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Dart 2.12.4\", ExpectedString: \"2.12.4\", Version: \"Dart SDK version: 2.12.4 (stable) (Thu Apr 15 12:26:53 2021 +0200) on \\\"macos_x64\\\"\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"dart\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.dart\",\n\t\t}\n\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tenv.On(\"HasCommand\", \"fvm\").Return(false)\n\n\t\td := &Dart{}\n\t\td.Init(props, env)\n\n\t\tassert.True(t, d.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, d.Template(), d), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/deno.go",
    "content": "package segments\n\ntype Deno struct {\n\tLanguage\n}\n\nfunc (d *Deno) Template() string {\n\treturn languageTemplate\n}\n\nfunc (d *Deno) Enabled() bool {\n\td.extensions = []string{\"*.js\", \"*.ts\", \"deno.json\"}\n\td.tooling = map[string]*cmd{\n\t\t\"deno\": {\n\t\t\texecutable: \"deno\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\td.defaultTooling = []string{\"deno\"}\n\td.versionURLTemplate = \"https://github.com/denoland/deno/releases/tag/v{{.Full}}\"\n\n\treturn d.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/deno_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDeno(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Deno 1.25.2\", ExpectedString: \"1.25.2\", Version: \"deno 1.25.2 (release, aarch64-apple-darwin)\\nv8 10.6.194.5\\ntypescript 4.7.4\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"deno\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.js\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\td := &Deno{}\n\t\td.Init(props, env)\n\t\tassert.True(t, d.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, d.Template(), d), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/docker.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"path/filepath\"\n\n\t\"slices\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\t// FetchContext is the property used to fetch the current docker context\n\tFetchContext options.Option = \"fetch_context\"\n)\n\ntype DockerConfig struct {\n\tCurrentContext string `json:\"currentContext\"`\n}\n\ntype Docker struct {\n\tBase\n\n\tContext string\n}\n\nfunc (d *Docker) Template() string {\n\treturn \" \\uf308 {{ .Context }} \"\n}\n\nfunc (d *Docker) envVars() []string {\n\treturn []string{\"DOCKER_MACHINE_NAME\", \"DOCKER_HOST\", \"DOCKER_CONTEXT\"}\n}\n\nfunc (d *Docker) configFiles() []string {\n\tfiles := []string{\n\t\tfilepath.Join(d.env.Home(), \".docker/config.json\"),\n\t}\n\n\tdockerConfig := d.env.Getenv(\"DOCKER_CONFIG\")\n\tif len(dockerConfig) > 0 {\n\t\tfiles = append(files, filepath.Join(dockerConfig, \"config.json\"))\n\t}\n\n\treturn files\n}\n\nfunc (d *Docker) Enabled() bool {\n\textensions := []string{\n\t\t\"compose.yml\",\n\t\t\"compose.yaml\",\n\t\t\"docker-compose.yml\",\n\t\t\"docker-compose.yaml\",\n\t\t\"Dockerfile\",\n\t}\n\n\textensions = d.options.StringArray(LanguageExtensions, extensions)\n\n\tdisplayMode := d.options.String(DisplayMode, DisplayModeContext)\n\tswitch displayMode {\n\tcase DisplayModeContext:\n\t\treturn d.fetchContext()\n\tcase DisplayModeFiles:\n\t\tif !slices.ContainsFunc(extensions, d.env.HasFiles) {\n\t\t\treturn false\n\t\t}\n\n\t\t// always respect the context fetching\n\t\tif d.options.Bool(FetchContext, true) {\n\t\t\t_ = d.fetchContext()\n\t\t}\n\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (d *Docker) fetchContext() bool {\n\t// Check if there is a non-empty environment variable named `DOCKER_HOST` or `DOCKER_CONTEXT`\n\t// These variables are set by the docker CLI and override the config file\n\t// Return the current context if it is not empty and not `default`\n\tfor _, v := range d.envVars() {\n\t\tcontext := d.env.Getenv(v)\n\t\tif len(context) > 0 && context != \"default\" {\n\t\t\td.Context = context\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// Check if there is a file named `$HOME/.docker/config.json` or `$DOCKER_CONFIG/config.json`\n\t// Return the current context if it is not empty and not `default`\n\tfor _, f := range d.configFiles() {\n\t\tdata := d.env.FileContent(f)\n\t\tif data == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar cfg DockerConfig\n\t\tif err := json.Unmarshal([]byte(data), &cfg); err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif len(cfg.CurrentContext) > 0 && cfg.CurrentContext != \"default\" {\n\t\t\td.Context = cfg.CurrentContext\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/docker_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n\tmock_ \"github.com/stretchr/testify/mock\"\n)\n\nfunc TestDockerContext(t *testing.T) {\n\ttype envVar struct {\n\t\tname  string\n\t\tvalue string\n\t}\n\tcases := []struct {\n\t\tEnvVar          envVar\n\t\tCase            string\n\t\tExpected        string\n\t\tConfigFile      string\n\t\tExpectedEnabled bool\n\t\tHasFiles        bool\n\t}{\n\t\t{Case: \"DOCKER_MACHINE_NAME\", Expected: \"alpine\", ExpectedEnabled: true, EnvVar: envVar{name: \"DOCKER_MACHINE_NAME\", value: \"alpine\"}},\n\t\t{Case: \"DOCKER_HOST\", Expected: \"alpine 2\", ExpectedEnabled: true, EnvVar: envVar{name: \"DOCKER_HOST\", value: \"alpine 2\"}},\n\t\t{Case: \"DOCKER_CONTEXT\", Expected: \"alpine 3\", ExpectedEnabled: true, EnvVar: envVar{name: \"DOCKER_HOST\", value: \"alpine 3\"}},\n\t\t{Case: \"DOCKER_CONTEXT - default\", ExpectedEnabled: false, EnvVar: envVar{name: \"DOCKER_HOST\", value: \"default\"}},\n\t\t{Case: \"no docker context active\", ExpectedEnabled: false},\n\t\t{Case: \"config file\", Expected: \"alpine\", ExpectedEnabled: true, HasFiles: true, ConfigFile: `{\"currentContext\": \"alpine\"}`},\n\t\t{Case: \"config file - default\", ExpectedEnabled: false, HasFiles: true, ConfigFile: `{\"currentContext\": \"default\"}`},\n\t\t{Case: \"config file - broken\", ExpectedEnabled: false, HasFiles: true, ConfigFile: `{`},\n\t}\n\n\tfor _, tc := range cases {\n\t\tdocker := &Docker{}\n\t\tenv := new(mock.Environment)\n\t\tdocker.Init(options.Map{}, env)\n\n\t\tfor _, v := range docker.envVars() {\n\t\t\tvar value string\n\t\t\tif v == tc.EnvVar.name {\n\t\t\t\tvalue = tc.EnvVar.value\n\t\t\t}\n\t\t\tenv.On(\"Getenv\", v).Return(value)\n\t\t}\n\n\t\tenv.On(\"Home\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"DOCKER_CONFIG\").Return(\"\")\n\t\tfor _, f := range docker.configFiles() {\n\t\t\tenv.On(\"HasFiles\", f).Return(tc.HasFiles)\n\t\t\tenv.On(\"FileContent\", f).Return(tc.ConfigFile)\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, docker.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.Expected, renderTemplate(env, \"{{ .Context }}\", docker), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestDockerFiles(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedEnabled bool\n\t\tHasFiles        bool\n\t}{\n\t\t{Case: \"compose.yml\", ExpectedEnabled: true, HasFiles: true},\n\t\t{Case: \"compose.yaml\", ExpectedEnabled: true, HasFiles: true},\n\t\t{Case: \"docker-compose.yml\", ExpectedEnabled: true, HasFiles: true},\n\t\t{Case: \"docker-compose.yaml\", ExpectedEnabled: true, HasFiles: true},\n\t\t{Case: \"Dockerfile\", ExpectedEnabled: true, HasFiles: true},\n\t\t{Case: \"docker-compose.yml - not found\", ExpectedEnabled: false, HasFiles: false},\n\t}\n\n\tfor _, tc := range cases {\n\t\tdocker := &Docker{}\n\t\tenv := new(mock.Environment)\n\t\tprops := options.Map{\n\t\t\tDisplayMode:  DisplayModeFiles,\n\t\t\tFetchContext: false,\n\t\t}\n\n\t\tdocker.Init(props, env)\n\n\t\tenv.On(\"HasFiles\", tc.Case).Return(true)\n\t\tenv.On(\"HasFiles\", mock_.Anything).Return(false)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, docker.Enabled(), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/dotnet.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/constants\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype globalJSON struct {\n\tSdk struct {\n\t\tVersion string `json:\"version\"`\n\t} `json:\"sdk\"`\n}\n\nconst (\n\t// FetchSDKVersion fetches the SDK version in global.json\n\tFetchSDKVersion options.Option = \"fetch_sdk_version\"\n)\n\ntype Dotnet struct {\n\tSDKVersion string\n\tLanguage\n\tUnsupported bool\n}\n\nfunc (d *Dotnet) Template() string {\n\treturn \" {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }} \"\n}\n\nfunc (d *Dotnet) Enabled() bool {\n\td.extensions = []string{\n\t\t\"*.cs\",\n\t\t\"*.csx\",\n\t\t\"*.vb\",\n\t\t\"*.sln\",\n\t\t\"*.slnx\",\n\t\t\"*.slnf\",\n\t\t\"*.csproj\",\n\t\t\"*.vbproj\",\n\t\t\"*.fs\",\n\t\t\"*.fsx\",\n\t\t\"*.fsproj\",\n\t\t\"global.json\",\n\t}\n\td.tooling = map[string]*cmd{\n\t\t\"dotnet\": {\n\t\t\texecutable: \"dotnet\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex: `(?P<version>((?P<major>0|[1-9]\\d*)\\.(?P<minor>0|[1-9]\\d*)\\.(?P<patch>0|[1-9]\\d*)` +\n\t\t\t\t`(?:-(?P<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?))`,\n\t\t},\n\t}\n\td.defaultTooling = []string{\"dotnet\"}\n\td.versionURLTemplate = \"https://github.com/dotnet/core/blob/main/release-notes/{{ .Major }}.{{ .Minor }}/{{ .Major }}.{{ .Minor }}.{{ substr 0 1 .Patch }}/{{ .Major }}.{{ .Minor }}.{{ substr 0 1 .Patch }}.md\" //nolint: lll\n\n\tenabled := d.Language.Enabled()\n\tif !enabled {\n\t\treturn false\n\t}\n\n\td.Unsupported = d.exitCode == constants.DotnetExitCode\n\n\tif !d.options.Bool(FetchSDKVersion, false) {\n\t\treturn true\n\t}\n\n\tfile, err := d.env.HasParentFilePath(\"global.json\", false)\n\tif err != nil {\n\t\treturn true\n\t}\n\n\tcontent := d.env.FileContent(file.Path)\n\n\tvar globalJSON globalJSON\n\tif err := json.Unmarshal([]byte(content), &globalJSON); err == nil {\n\t\td.SDKVersion = globalJSON.Sdk.Version\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/dotnet_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/constants\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestDotnetSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tVersion  string\n\t\tExitCode int\n\t}{\n\t\t{Case: \"Unsupported version\", Expected: \"\\uf071\", ExitCode: constants.DotnetExitCode, Version: \"3.1.402\"},\n\t\t{Case: \"Regular version\", Expected: \"3.1.402\", Version: \"3.1.402\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"dotnet\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.cs\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.ExitCode != 0 {\n\t\t\tenv.Unset(\"RunCommand\")\n\t\t\terr := &runtime.CommandError{ExitCode: tc.ExitCode}\n\t\t\tenv.On(\"RunCommand\", \"dotnet\", []string{\"--version\"}).Return(\"\", err)\n\t\t}\n\n\t\tdotnet := &Dotnet{}\n\t\tdotnet.Init(props, env)\n\n\t\tassert.True(t, dotnet.Enabled())\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, dotnet.Template(), dotnet), tc.Case)\n\t}\n}\n\nfunc TestDotnetSDKVersion(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tGlobalJSON     string\n\t\tExpectedSDK    string\n\t\tGlobalJSONPath string\n\t\tFetchSDK       bool\n\t\tHasGlobalJSON  bool\n\t}{\n\t\t{\n\t\t\tCase:        \"Do not fetch SDK version\",\n\t\t\tFetchSDK:    false,\n\t\t\tExpectedSDK: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:        \"No global.json found\",\n\t\t\tFetchSDK:    true,\n\t\t\tExpectedSDK: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Valid global.json\",\n\t\t\tFetchSDK:       true,\n\t\t\tGlobalJSON:     `{\"sdk\": {\"version\": \"6.0.100\"}}`,\n\t\t\tExpectedSDK:    \"6.0.100\",\n\t\t\tHasGlobalJSON:  true,\n\t\t\tGlobalJSONPath: \"/test/global.json\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Invalid global.json\",\n\t\t\tFetchSDK:       true,\n\t\t\tGlobalJSON:     `invalid json`,\n\t\t\tExpectedSDK:    \"\",\n\t\t\tHasGlobalJSON:  true,\n\t\t\tGlobalJSONPath: \"/test/global.json\",\n\t\t},\n\t}\n\n\tparams := &mockedLanguageParams{\n\t\tcmd:           \"dotnet\",\n\t\tversionParam:  \"--version\",\n\t\tversionOutput: \"6.0.100\",\n\t\textension:     \"*.cs\",\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tFetchSDKVersion:      tc.FetchSDK,\n\t\t\toptions.FetchVersion: false,\n\t\t}\n\n\t\tenv, _ := getMockedLanguageEnv(params)\n\n\t\tif tc.HasGlobalJSON {\n\t\t\tfile := &runtime.FileInfo{\n\t\t\t\tPath: tc.GlobalJSONPath,\n\t\t\t}\n\t\t\tenv.On(\"HasParentFilePath\", \"global.json\", false).Return(file, nil)\n\t\t\tenv.On(\"FileContent\", tc.GlobalJSONPath).Return(tc.GlobalJSON)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \"global.json\", false).Return(&runtime.FileInfo{}, errors.New(\"file not found\"))\n\t\t}\n\n\t\tdotnet := &Dotnet{}\n\t\tdotnet.Init(props, env)\n\n\t\tassert.True(t, dotnet.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedSDK, dotnet.SDKVersion, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/elixir.go",
    "content": "package segments\n\ntype Elixir struct {\n\tLanguage\n}\n\nfunc (e *Elixir) Template() string {\n\treturn languageTemplate\n}\n\nfunc (e *Elixir) Enabled() bool {\n\te.extensions = []string{\"*.ex\", \"*.exs\"}\n\te.tooling = map[string]*cmd{\n\t\t\"asdf\": {\n\t\t\texecutable: \"asdf\",\n\t\t\targs:       []string{\"current\", \"elixir\"},\n\t\t\tregex:      `elixir\\s+(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))[^\\s]*\\s+`,\n\t\t},\n\t\t\"elixir\": {\n\t\t\texecutable: \"elixir\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Elixir (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\te.defaultTooling = []string{\"asdf\", \"elixir\"}\n\te.versionURLTemplate = \"https://github.com/elixir-lang/elixir/releases/tag/v{{ .Full }}\"\n\n\treturn e.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/elixir_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestElixir(t *testing.T) {\n\tcases := []struct {\n\t\tCase                string\n\t\tExpectedString      string\n\t\tElixirVersionOutput string\n\t\tAsdfVersionOutput   string\n\t\tHasAsdf             bool\n\t\tAsdfExitCode        int\n\t}{\n\t\t{\n\t\t\tCase:                \"Version without asdf\",\n\t\t\tExpectedString:      \"1.14.2\",\n\t\t\tElixirVersionOutput: \"Erlang/OTP 25 [erts-13.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]\\n\\nElixir 1.14.2 (compiled with Erlang/OTP 25)\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"Version with asdf\",\n\t\t\tExpectedString:      \"1.14.2\",\n\t\t\tHasAsdf:             true,\n\t\t\tAsdfVersionOutput:   \"elixir          1.14.2-otp-25   /path/to/.tool-versions\",\n\t\t\tElixirVersionOutput: \"Should not be used\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"Version with asdf not set: should fall back to elixir --version\",\n\t\t\tExpectedString:      \"1.14.2\",\n\t\t\tHasAsdf:             true,\n\t\t\tAsdfVersionOutput:   \"elixir             ______          No version is set. Run \\\"asdf <global|shell|local> elixir <version>\\\"\",\n\t\t\tAsdfExitCode:        126,\n\t\t\tElixirVersionOutput: \"Erlang/OTP 25 [erts-13.1.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit] [dtrace]\\n\\nElixir 1.14.2 (compiled with Erlang/OTP 25)\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"elixir\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.ElixirVersionOutput,\n\t\t\textension:     \"*.ex\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"HasCommand\", \"asdf\").Return(tc.HasAsdf)\n\t\tvar asdfErr error\n\t\tif tc.AsdfExitCode != 0 {\n\t\t\tasdfErr = &runtime.CommandError{ExitCode: tc.AsdfExitCode}\n\t\t}\n\t\tenv.On(\"RunCommand\", \"asdf\", []string{\"current\", \"elixir\"}).Return(tc.AsdfVersionOutput, asdfErr)\n\n\t\tr := &Elixir{}\n\t\tr.Init(props, env)\n\t\tassert.True(t, r.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, r.Template(), r), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/executiontime.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\tlang \"golang.org/x/text/language\"\n\t\"golang.org/x/text/message\"\n)\n\ntype Executiontime struct {\n\tBase\n\n\tFormattedMs string\n\tMs          int64\n}\n\n// DurationStyle how to display the time\ntype DurationStyle string\n\nconst (\n\t// ThresholdProperty represents minimum duration (milliseconds) required to enable this segment\n\tThresholdProperty options.Option = \"threshold\"\n\t// Austin milliseconds short\n\tAustin DurationStyle = \"austin\"\n\t// Roundrock milliseconds long\n\tRoundrock DurationStyle = \"roundrock\"\n\t// Dallas milliseconds full\n\tDallas DurationStyle = \"dallas\"\n\t// Galveston hour\n\tGalveston DurationStyle = \"galveston\"\n\t// Galveston hour\n\tGalvestonMs DurationStyle = \"galvestonms\"\n\t// Houston hour and milliseconds\n\tHouston DurationStyle = \"houston\"\n\t// Amarillo seconds\n\tAmarillo DurationStyle = \"amarillo\"\n\t// Round will round the output of the format\n\tRound DurationStyle = \"round\"\n\t// Always 7 character width\n\tLucky7 = \"lucky7\"\n\t// ISO8601 ISO 8601 duration format (seconds)\n\tISO8601 DurationStyle = \"iso8601\"\n\t// ISO8601Ms ISO 8601 duration format with milliseconds\n\tISO8601Ms DurationStyle = \"iso8601ms\"\n\n\tsecond           = 1000\n\tminute           = 60000\n\thour             = 3600000\n\tday              = 86400000\n\tsecondsPerMinute = 60\n\tminutesPerHour   = 60\n\thoursPerDay      = 24\n)\n\nfunc (t *Executiontime) Enabled() bool {\n\talwaysEnabled := t.options.Bool(options.AlwaysEnabled, false)\n\texecutionTimeMs := t.env.ExecutionTime()\n\tthresholdMs := t.options.Float64(ThresholdProperty, float64(500))\n\tif !alwaysEnabled && executionTimeMs < thresholdMs {\n\t\treturn false\n\t}\n\tstyle := DurationStyle(t.options.String(options.Style, string(Austin)))\n\tt.Ms = int64(executionTimeMs)\n\tt.FormattedMs = t.formatDuration(style)\n\treturn t.FormattedMs != \"\"\n}\n\nfunc (t *Executiontime) Template() string {\n\treturn \" {{ .FormattedMs }} \"\n}\n\nfunc (t *Executiontime) formatDuration(style DurationStyle) string {\n\tswitch style {\n\tcase Austin:\n\t\treturn t.formatDurationAustin()\n\tcase Roundrock:\n\t\treturn t.formatDurationRoundrock()\n\tcase Dallas:\n\t\treturn t.formatDurationDallas()\n\tcase Galveston:\n\t\treturn t.formatDurationGalveston()\n\tcase GalvestonMs:\n\t\treturn t.formatDurationGalvestonMs()\n\tcase Houston:\n\t\treturn t.formatDurationHouston()\n\tcase Amarillo:\n\t\treturn t.formatDurationAmarillo()\n\tcase Round:\n\t\treturn t.formatDurationRound()\n\tcase Lucky7:\n\t\treturn t.formatDurationLucky7()\n\tcase ISO8601:\n\t\treturn t.formatDurationISO8601()\n\tcase ISO8601Ms:\n\t\treturn t.formatDurationISO8601Ms()\n\tdefault:\n\t\treturn fmt.Sprintf(\"Style: %s is not available\", style)\n\t}\n}\n\nfunc (t *Executiontime) formatDurationAustin() string {\n\tif t.Ms < second {\n\t\treturn fmt.Sprintf(\"%dms\", t.Ms%second)\n\t}\n\n\tseconds := float64(t.Ms%minute) / second\n\tresult := strconv.FormatFloat(seconds, 'f', -1, 64) + \"s\"\n\n\tif t.Ms >= minute {\n\t\tresult = fmt.Sprintf(\"%dm %s\", t.Ms/minute%secondsPerMinute, result)\n\t}\n\tif t.Ms >= hour {\n\t\tresult = fmt.Sprintf(\"%dh %s\", t.Ms/hour%hoursPerDay, result)\n\t}\n\tif t.Ms >= day {\n\t\tresult = fmt.Sprintf(\"%dd %s\", t.Ms/day, result)\n\t}\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationRoundrock() string {\n\tresult := fmt.Sprintf(\"%dms\", t.Ms%second)\n\tif t.Ms >= second {\n\t\tresult = fmt.Sprintf(\"%ds %s\", t.Ms/second%secondsPerMinute, result)\n\t}\n\tif t.Ms >= minute {\n\t\tresult = fmt.Sprintf(\"%dm %s\", t.Ms/minute%minutesPerHour, result)\n\t}\n\tif t.Ms >= hour {\n\t\tresult = fmt.Sprintf(\"%dh %s\", t.Ms/hour%hoursPerDay, result)\n\t}\n\tif t.Ms >= day {\n\t\tresult = fmt.Sprintf(\"%dd %s\", t.Ms/day, result)\n\t}\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationDallas() string {\n\tseconds := float64(t.Ms%minute) / second\n\tresult := strconv.FormatFloat(seconds, 'f', -1, 64)\n\n\tif t.Ms >= minute {\n\t\tresult = fmt.Sprintf(\"%d:%s\", t.Ms/minute%minutesPerHour, result)\n\t}\n\tif t.Ms >= hour {\n\t\tresult = fmt.Sprintf(\"%d:%s\", t.Ms/hour%hoursPerDay, result)\n\t}\n\tif t.Ms >= day {\n\t\tresult = fmt.Sprintf(\"%d:%s\", t.Ms/day, result)\n\t}\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationGalveston() string {\n\tresult := fmt.Sprintf(\"%02d:%02d:%02d\", t.Ms/hour, t.Ms/minute%minutesPerHour, t.Ms%minute/second)\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationGalvestonMs() string {\n\tmillies := t.Ms % second\n\tresult := fmt.Sprintf(\"%02d:%02d:%02d:%03d\", t.Ms/hour, t.Ms/minute%minutesPerHour, t.Ms%minute/second, millies)\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationHouston() string {\n\tmilliseconds := \".0\"\n\tif t.Ms%second > 0 {\n\t\t// format milliseconds as a string with truncated trailing zeros\n\t\tmilliseconds = strconv.FormatFloat(float64(t.Ms%second)/second, 'f', -1, 64)\n\t\t// at this point milliseconds looks like \"0.5\". remove the leading \"0\"\n\t\tif len(milliseconds) >= 1 {\n\t\t\tmilliseconds = milliseconds[1:]\n\t\t}\n\t}\n\n\tresult := fmt.Sprintf(\"%02d:%02d:%02d%s\", t.Ms/hour, t.Ms/minute%minutesPerHour, t.Ms%minute/second, milliseconds)\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationAmarillo() string {\n\t// wholeNumber represents the value to the left of the decimal point (seconds)\n\twholeNumber := t.Ms / second\n\t// decimalNumber represents the value to the right of the decimal point (milliseconds)\n\tdecimalNumber := float64(t.Ms%second) / second\n\n\t// format wholeNumber as a string with thousands separators\n\tprinter := message.NewPrinter(lang.English)\n\tresult := printer.Sprintf(\"%d\", wholeNumber)\n\n\tif decimalNumber > 0 {\n\t\t// format decimalNumber as a string with truncated trailing zeros\n\t\tdecimalResult := strconv.FormatFloat(decimalNumber, 'f', -1, 64)\n\t\t// at this point decimalResult looks like \"0.5\"\n\t\t// remove the leading \"0\" and append\n\t\tif len(decimalResult) >= 1 {\n\t\t\tresult += decimalResult[1:]\n\t\t}\n\t}\n\tresult += \"s\"\n\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationRound() string {\n\ttoRoundString := func(one, two int64, oneText, twoText string) string {\n\t\tif two == 0 {\n\t\t\treturn fmt.Sprintf(\"%d%s\", one, oneText)\n\t\t}\n\t\treturn fmt.Sprintf(\"%d%s %d%s\", one, oneText, two, twoText)\n\t}\n\thours := t.Ms / hour % hoursPerDay\n\tif t.Ms >= day {\n\t\treturn toRoundString(t.Ms/day, hours, \"d\", \"h\")\n\t}\n\tminutes := t.Ms / minute % secondsPerMinute\n\tif t.Ms >= hour {\n\t\treturn toRoundString(hours, minutes, \"h\", \"m\")\n\t}\n\tseconds := (t.Ms % minute) / second\n\tif t.Ms >= minute {\n\t\treturn toRoundString(minutes, seconds, \"m\", \"s\")\n\t}\n\tif t.Ms >= second {\n\t\treturn fmt.Sprintf(\"%ds\", seconds)\n\t}\n\treturn fmt.Sprintf(\"%dms\", t.Ms%second)\n}\n\nfunc (t *Executiontime) formatDurationLucky7() string {\n\t// https://github.com/JanDeDobbeleer/oh-my-posh/issues/3970\n\t// execution time will always be 7 characters long\n\t// decimal point will be at the same location (3rd space or str[2])\n\t// seconds and milliseconds will be aligned\n\t// [m, s], [h, m], [d, h] will be aligned\n\tif t.Ms < second {\n\t\t//   999ms\n\t\t// 1234567\n\t\treturn fmt.Sprintf(\"%5dms\", t.Ms%second)\n\t}\n\n\tif t.Ms < minute {\n\t\t// 12.34s\n\t\t// 1234567\n\n\t\t//  1.23s\n\t\t// 1230 (= 1230ms)\n\t\t// ^ use Sprintf pad left space\n\t\t//  1230\n\t\t// from here, just take 1, 23 of 230, and append s and ' '\n\n\t\tresult := fmt.Sprintf(\"%5d\", t.Ms)\n\n\t\treturn result[:2] + \".\" + result[2:4] + \"s \"\n\t}\n\n\tif t.Ms < hour {\n\t\tm := t.Ms / minute\n\t\ts := t.Ms % minute / second\n\n\t\treturn fmt.Sprintf(\"%2dm %2ds\", m, s)\n\t}\n\n\tif t.Ms < day {\n\t\th := t.Ms / hour\n\t\tm := t.Ms % hour / minute\n\n\t\treturn fmt.Sprintf(\"%2dh %2dm\", h, m)\n\t}\n\n\tif t.Ms < 100*day {\n\t\td := t.Ms / day\n\t\th := t.Ms % day / hour\n\n\t\treturn fmt.Sprintf(\"%2dd %2dh\", d, h)\n\t}\n\n\t// I have no Idea how you got here\n\t// return \"   ∞   \"\n\td := t.Ms / day\n\treturn fmt.Sprintf(\"%6dd\", d)\n}\n\nfunc (t *Executiontime) formatDurationISO8601() string {\n\t// ISO 8601 duration format: PT[n]H[n]M[n]S\n\t// Examples: PT13M12S, PT1H30M45S\n\tresult := \"PT\"\n\n\thours := t.Ms / hour\n\tminutes := (t.Ms % hour) / minute\n\tseconds := float64(t.Ms%minute) / second\n\n\troundedSeconds := int64(seconds)\n\tif t.Ms%second >= second/2 {\n\t\troundedSeconds++\n\t}\n\n\t// Handle potential overflow from rounding\n\tif roundedSeconds >= secondsPerMinute {\n\t\troundedSeconds = 0\n\t\tminutes++\n\t\tif minutes >= minutesPerHour {\n\t\t\tminutes = 0\n\t\t\thours++\n\t\t}\n\t}\n\n\tif hours > 0 {\n\t\tresult += fmt.Sprintf(\"%dH\", hours)\n\t}\n\tif minutes > 0 {\n\t\tresult += fmt.Sprintf(\"%dM\", minutes)\n\t}\n\tif roundedSeconds > 0 || (hours == 0 && minutes == 0) {\n\t\tresult += fmt.Sprintf(\"%dS\", roundedSeconds)\n\t}\n\n\treturn result\n}\n\nfunc (t *Executiontime) formatDurationISO8601Ms() string {\n\t// ISO 8601 duration format with milliseconds: PT[n]H[n]M[n]S\n\t// Examples: PT13M12.1S, PT1H30M45.123S\n\tresult := \"PT\"\n\n\thours := t.Ms / hour\n\tminutes := (t.Ms % hour) / minute\n\tseconds := float64(t.Ms%minute) / second\n\n\tif hours > 0 {\n\t\tresult += fmt.Sprintf(\"%dH\", hours)\n\t}\n\tif minutes > 0 {\n\t\tresult += fmt.Sprintf(\"%dM\", minutes)\n\t}\n\tif seconds > 0 || (hours == 0 && minutes == 0) {\n\t\tsecondsStr := strconv.FormatFloat(seconds, 'f', -1, 64)\n\t\tresult += fmt.Sprintf(\"%sS\", secondsStr)\n\t}\n\n\treturn result\n}\n"
  },
  {
    "path": "src/segments/executiontime_test.go",
    "content": "package segments\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestExecutionTimeWriterDefaultThresholdEnabled(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(1337)\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(options.Map{}, env)\n\n\tassert.True(t, executionTime.Enabled())\n}\n\nfunc TestExecutionTimeWriterDefaultThresholdDisabled(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(1)\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(options.Map{}, env)\n\n\tassert.False(t, executionTime.Enabled())\n}\n\nfunc TestExecutionTimeWriterCustomThresholdEnabled(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(99)\n\tprops := options.Map{\n\t\tThresholdProperty: float64(10),\n\t}\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(props, env)\n\n\tassert.True(t, executionTime.Enabled())\n}\n\nfunc TestExecutionTimeWriterCustomThresholdDisabled(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(99)\n\tprops := options.Map{\n\t\tThresholdProperty: float64(100),\n\t}\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(props, env)\n\n\tassert.False(t, executionTime.Enabled())\n}\n\nfunc TestExecutionTimeWriterDuration(t *testing.T) {\n\tinput := 1337\n\texpected := \"1.337s\"\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(input)\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(options.Map{}, env)\n\n\texecutionTime.Enabled()\n\tassert.Equal(t, expected, executionTime.FormattedMs)\n}\n\nfunc TestExecutionTimeWriterDuration2(t *testing.T) {\n\tinput := 13371337\n\texpected := \"3h 42m 51.337s\"\n\tenv := new(mock.Environment)\n\tenv.On(\"ExecutionTime\").Return(input)\n\n\texecutionTime := &Executiontime{}\n\texecutionTime.Init(options.Map{}, env)\n\n\texecutionTime.Enabled()\n\tassert.Equal(t, expected, executionTime.FormattedMs)\n}\n\nfunc TestExecutionTimeFormatDurationAustin(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"1ms\"},\n\t\t{Input: \"0.1s\", Expected: \"100ms\"},\n\t\t{Input: \"1s\", Expected: \"1s\"},\n\t\t{Input: \"2.1s\", Expected: \"2.1s\"},\n\t\t{Input: \"1m\", Expected: \"1m 0s\"},\n\t\t{Input: \"3m2.1s\", Expected: \"3m 2.1s\"},\n\t\t{Input: \"1h\", Expected: \"1h 0m 0s\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"4h 3m 2.1s\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"5d 4h 3m 2.1s\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"5d 4h 3m 2s\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationAustin()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatDurationRoundrock(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"1ms\"},\n\t\t{Input: \"0.1s\", Expected: \"100ms\"},\n\t\t{Input: \"1s\", Expected: \"1s 0ms\"},\n\t\t{Input: \"2.1s\", Expected: \"2s 100ms\"},\n\t\t{Input: \"1m\", Expected: \"1m 0s 0ms\"},\n\t\t{Input: \"3m2.1s\", Expected: \"3m 2s 100ms\"},\n\t\t{Input: \"1h\", Expected: \"1h 0m 0s 0ms\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"4h 3m 2s 100ms\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"5d 4h 3m 2s 100ms\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"5d 4h 3m 2s 0ms\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationRoundrock()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatDallas(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"0.001\"},\n\t\t{Input: \"0.1s\", Expected: \"0.1\"},\n\t\t{Input: \"1s\", Expected: \"1\"},\n\t\t{Input: \"2.1s\", Expected: \"2.1\"},\n\t\t{Input: \"1m\", Expected: \"1:0\"},\n\t\t{Input: \"3m2.1s\", Expected: \"3:2.1\"},\n\t\t{Input: \"1h\", Expected: \"1:0:0\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"4:3:2.1\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"5:4:3:2.1\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"5:4:3:2\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationDallas()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatGalveston(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"00:00:00\"},\n\t\t{Input: \"0.1s\", Expected: \"00:00:00\"},\n\t\t{Input: \"1s\", Expected: \"00:00:01\"},\n\t\t{Input: \"2.1s\", Expected: \"00:00:02\"},\n\t\t{Input: \"1m\", Expected: \"00:01:00\"},\n\t\t{Input: \"3m2.1s\", Expected: \"00:03:02\"},\n\t\t{Input: \"1h\", Expected: \"01:00:00\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"04:03:02\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"124:03:02\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"124:03:02\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationGalveston()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatGalvestonMs(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"00:00:00:001\"},\n\t\t{Input: \"0.1s\", Expected: \"00:00:00:100\"},\n\t\t{Input: \"1s\", Expected: \"00:00:01:000\"},\n\t\t{Input: \"2.1s\", Expected: \"00:00:02:100\"},\n\t\t{Input: \"1m\", Expected: \"00:01:00:000\"},\n\t\t{Input: \"3m2.1s\", Expected: \"00:03:02:100\"},\n\t\t{Input: \"1h\", Expected: \"01:00:00:000\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"04:03:02:100\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"124:03:02:100\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"124:03:02:000\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationGalvestonMs()\n\t\tassert.Equal(t, tc.Expected, output, tc.Input)\n\t}\n}\n\nfunc TestExecutionTimeFormatHouston(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"00:00:00.001\"},\n\t\t{Input: \"0.1s\", Expected: \"00:00:00.1\"},\n\t\t{Input: \"1s\", Expected: \"00:00:01.0\"},\n\t\t{Input: \"2.1s\", Expected: \"00:00:02.1\"},\n\t\t{Input: \"1m\", Expected: \"00:01:00.0\"},\n\t\t{Input: \"3m2.1s\", Expected: \"00:03:02.1\"},\n\t\t{Input: \"1h\", Expected: \"01:00:00.0\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"04:03:02.1\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"124:03:02.1\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"124:03:02.0\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationHouston()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatAmarillo(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"0.001s\"},\n\t\t{Input: \"0.1s\", Expected: \"0.1s\"},\n\t\t{Input: \"1s\", Expected: \"1s\"},\n\t\t{Input: \"2.1s\", Expected: \"2.1s\"},\n\t\t{Input: \"1m\", Expected: \"60s\"},\n\t\t{Input: \"3m2.1s\", Expected: \"182.1s\"},\n\t\t{Input: \"1h\", Expected: \"3,600s\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"14,582.1s\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"446,582.1s\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"446,582s\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationAmarillo()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatDurationRound(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"1ms\"},\n\t\t{Input: \"0.1s\", Expected: \"100ms\"},\n\t\t{Input: \"1s\", Expected: \"1s\"},\n\t\t{Input: \"2.1s\", Expected: \"2s\"},\n\t\t{Input: \"1m\", Expected: \"1m\"},\n\t\t{Input: \"3m2.1s\", Expected: \"3m 2s\"},\n\t\t{Input: \"1h\", Expected: \"1h\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"4h 3m\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"5d 4h\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"5d 4h\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationRound()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n}\n\nfunc TestExecutionTimeFormatDurationLucky7(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{\n\t\t\tInput:    \"0.001s\",\n\t\t\tExpected: \"    1ms\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"0.1s\",\n\t\t\tExpected: \"  100ms\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"1s\",\n\t\t\tExpected: \" 1.00s \",\n\t\t},\n\t\t{\n\t\t\tInput:    \"2.1s\",\n\t\t\tExpected: \" 2.10s \",\n\t\t},\n\t\t{\n\t\t\tInput:    \"1m\",\n\t\t\tExpected: \" 1m  0s\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"3m2.1s\",\n\t\t\tExpected: \" 3m  2s\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"1h\",\n\t\t\tExpected: \" 1h  0m\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"4h3m2.1s\",\n\t\t\tExpected: \" 4h  3m\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"124h3m2.1s\",\n\t\t\tExpected: \" 5d  4h\",\n\t\t},\n\t\t{\n\t\t\tInput:    \"124h3m2.0s\",\n\t\t\tExpected: \" 5d  4h\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationLucky7()\n\t\tassert.Equal(t, tc.Expected, output)\n\t}\n\n\t// Extra fuzz test\n\tvar timestamp int64 = 1\n\tvar ms1000days int64 = 1000 * 24 * 60 * 60 * 1000\n\n\t// log(ms1000days, 1.5) is approx 62.1\n\tfor timestamp < ms1000days {\n\t\ttimestamp = int64(math.Ceil(float64(timestamp) * 1.5))\n\n\t\texecutionTime := (&Executiontime{\n\t\t\tMs: timestamp,\n\t\t}).formatDurationLucky7()\n\n\t\t// Lucky 7!!\n\t\tassert.Equal(t, len(executionTime), 7)\n\t}\n}\n\nfunc TestExecutionTimeFormatISO8601(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"PT0S\"},\n\t\t{Input: \"0.1s\", Expected: \"PT0S\"},\n\t\t{Input: \"0.5s\", Expected: \"PT1S\"},\n\t\t{Input: \"1s\", Expected: \"PT1S\"},\n\t\t{Input: \"2.1s\", Expected: \"PT2S\"},\n\t\t{Input: \"2.6s\", Expected: \"PT3S\"},\n\t\t{Input: \"1m\", Expected: \"PT1M\"},\n\t\t{Input: \"3m2.1s\", Expected: \"PT3M2S\"},\n\t\t{Input: \"3m2.6s\", Expected: \"PT3M3S\"},\n\t\t{Input: \"1h\", Expected: \"PT1H\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"PT4H3M2S\"},\n\t\t{Input: \"124h3m2.1s\", Expected: \"PT124H3M2S\"},\n\t\t{Input: \"124h3m2.0s\", Expected: \"PT124H3M2S\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationISO8601()\n\t\tassert.Equal(t, tc.Expected, output, \"Input: %s\", tc.Input)\n\t}\n}\n\nfunc TestExecutionTimeFormatISO8601Ms(t *testing.T) {\n\tcases := []struct {\n\t\tInput    string\n\t\tExpected string\n\t}{\n\t\t{Input: \"0.001s\", Expected: \"PT0.001S\"},\n\t\t{Input: \"0.1s\", Expected: \"PT0.1S\"},\n\t\t{Input: \"1s\", Expected: \"PT1S\"},\n\t\t{Input: \"2.1s\", Expected: \"PT2.1S\"},\n\t\t{Input: \"2.123s\", Expected: \"PT2.123S\"},\n\t\t{Input: \"1m\", Expected: \"PT1M\"},\n\t\t{Input: \"3m2.1s\", Expected: \"PT3M2.1S\"},\n\t\t{Input: \"3m2.123s\", Expected: \"PT3M2.123S\"},\n\t\t{Input: \"1h\", Expected: \"PT1H\"},\n\t\t{Input: \"4h3m2.1s\", Expected: \"PT4H3M2.1S\"},\n\t\t{Input: \"124h3m2.123s\", Expected: \"PT124H3M2.123S\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tduration, _ := time.ParseDuration(tc.Input)\n\t\texecutionTime := &Executiontime{}\n\t\texecutionTime.Ms = duration.Milliseconds()\n\t\toutput := executionTime.formatDurationISO8601Ms()\n\t\tassert.Equal(t, tc.Expected, output, \"Input: %s\", tc.Input)\n\t}\n}\n"
  },
  {
    "path": "src/segments/firebase.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nconst (\n\tFIREBASENOACTIVECONFIG = \"NO ACTIVE CONFIG FOUND\"\n)\n\ntype Firebase struct {\n\tBase\n\n\tProject string\n}\n\ntype FirebaseData struct {\n\tActiveProject map[string]string `json:\"activeProjects\"`\n}\n\nfunc (f *Firebase) Template() string {\n\treturn \" {{ .Project}} \"\n}\n\nfunc (f *Firebase) Enabled() bool {\n\tcfgDir := filepath.Join(f.env.Home(), \".config\", \"configstore\")\n\tconfigFile, err := f.getActiveConfig(cfgDir)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tdata, err := f.getFirebaseData(configFile)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\t// Within the activeProjects is a key value pair\n\t// of the path to the project and the project name\n\n\t// Test if the current directory is a project path\n\t// and if it is, return the project name\n\tfor key, value := range data.ActiveProject {\n\t\tif strings.HasPrefix(f.env.Pwd(), key) {\n\t\t\tf.Project = value\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (f *Firebase) getActiveConfig(cfgDir string) (string, error) {\n\tactiveConfigFile := filepath.Join(cfgDir, \"firebase-tools.json\")\n\tactiveConfigData := f.env.FileContent(activeConfigFile)\n\tif activeConfigData == \"\" {\n\t\treturn \"\", errors.New(FIREBASENOACTIVECONFIG)\n\t}\n\treturn activeConfigData, nil\n}\n\nfunc (f *Firebase) getFirebaseData(configFile string) (*FirebaseData, error) {\n\tvar data FirebaseData\n\n\terr := json.Unmarshal([]byte(configFile), &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &data, nil\n}\n"
  },
  {
    "path": "src/segments/firebase_test.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFirebaseSegment(t *testing.T) {\n\tconfig := `{\n\t\t\"activeProjects\": {\n\t\t\t\"path\": \"project-name\"\n\t\t}\n\t}`\n\tcases := []struct {\n\t\tCase            string\n\t\tActiveConfig    string\n\t\tActivePath      string\n\t\tExpectedString  string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"happy path\",\n\t\t\tExpectedEnabled: true,\n\t\t\tActiveConfig:    config,\n\t\t\tActivePath:      \"path\",\n\t\t\tExpectedString:  \"project-name\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"happy subpath\",\n\t\t\tExpectedEnabled: true,\n\t\t\tActiveConfig:    config,\n\t\t\tActivePath:      \"path/subpath\",\n\t\t\tExpectedString:  \"project-name\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"no active config\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"empty config\",\n\t\t\tActiveConfig:    \"{}\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"bad config\",\n\t\t\tActiveConfig:    \"{bad}\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(\"home\")\n\t\tenv.On(\"Pwd\").Return(tc.ActivePath)\n\t\tfcPath := filepath.Join(\"home\", \".config\", \"configstore\", \"firebase-tools.json\")\n\t\tenv.On(\"FileContent\", fcPath).Return(tc.ActiveConfig)\n\n\t\tf := &Firebase{}\n\t\tf.Init(options.Map{}, env)\n\n\t\tf.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, f.Enabled())\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, f.Template(), f), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestGetFirebaseActiveConfig(t *testing.T) {\n\tdata :=\n\t\t`{\n\t\t\t\"activeProjects\": {\n\t\t\t\t\"path\": \"project-name\"\n\t\t\t}\n\t\t}`\n\tcases := []struct {\n\t\tCase           string\n\t\tActiveConfig   string\n\t\tExpectedString string\n\t\tExpectedError  string\n\t}{\n\t\t{\n\t\t\tCase:           \"happy path\",\n\t\t\tActiveConfig:   data,\n\t\t\tExpectedString: data,\n\t\t},\n\t\t{\n\t\t\tCase:          \"no active config\",\n\t\t\tActiveConfig:  \"\",\n\t\t\tExpectedError: FIREBASENOACTIVECONFIG,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(\"home\")\n\t\tconfigPath := filepath.Join(\"home\", \".config\", \"configstore\")\n\t\tcontentPath := filepath.Join(configPath, \"firebase-tools.json\")\n\t\tenv.On(\"FileContent\", contentPath).Return(tc.ActiveConfig)\n\n\t\tf := &Firebase{}\n\t\tf.Init(options.Map{}, env)\n\n\t\tgot, err := f.getActiveConfig(configPath)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t\tif len(tc.ExpectedError) > 0 {\n\t\t\tassert.EqualError(t, err, tc.ExpectedError, tc.Case)\n\t\t} else {\n\t\t\tassert.NoError(t, err, tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/flutter.go",
    "content": "package segments\n\ntype Flutter struct {\n\tLanguage\n}\n\nfunc (f *Flutter) Template() string {\n\treturn languageTemplate\n}\n\nfunc (f *Flutter) Enabled() bool {\n\tf.extensions = dartExtensions\n\tf.folders = dartFolders\n\tf.tooling = map[string]*cmd{\n\t\t\"fvm\": {\n\t\t\texecutable: \"fvm\",\n\t\t\targs:       []string{\"flutter\", \"--version\"},\n\t\t\tregex:      `Flutter (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t\t\"flutter\": {\n\t\t\texecutable: \"flutter\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Flutter (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tf.defaultTooling = []string{\"fvm\", \"flutter\"}\n\tf.versionURLTemplate = \"https://github.com/flutter/flutter/releases/tag/{{ .Major }}.{{ .Minor }}.{{ .Patch }}\"\n\n\treturn f.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/flutter_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFlutter(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Flutter 2.10.4\", ExpectedString: \"2.10.4\", Version: \"Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"flutter\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.dart\",\n\t\t}\n\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tenv.On(\"HasCommand\", \"fvm\").Return(false)\n\n\t\td := &Flutter{}\n\t\td.Init(props, env)\n\n\t\tassert.True(t, d.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, d.Template(), d), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/fortran.go",
    "content": "package segments\n\ntype Fortran struct {\n\tLanguage\n}\n\nfunc (f *Fortran) Template() string {\n\treturn languageTemplate\n}\n\nfunc (f *Fortran) Enabled() bool {\n\tf.extensions = []string{\n\t\t\"*.f\", \"*.for\", \"*.fpp\",\n\t\t\"*.f77\", \"*.f90\", \"*.f95\",\n\t\t\"*.f03\", \"*.f08\",\n\t\t\"*.F\", \"*.FOR\", \"*.FPP\",\n\t\t\"*.F77\", \"*.F90\", \"*.F95\",\n\t\t\"*.F03\", \"*.F08\",\n\t\t\"fpm.toml\",\n\t}\n\tf.tooling = map[string]*cmd{\n\t\t\"gfortran\": {\n\t\t\texecutable: \"gfortran\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `GNU Fortran \\(.*\\) (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tf.defaultTooling = []string{\"gfortran\"}\n\n\treturn f.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/fortran_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFortran(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{\n\t\t\tCase:           \"GNU Fortran 10.2.1 Debian\",\n\t\t\tExpectedString: \"10.2.1\",\n\t\t\tVersion: `GNU Fortran (Debian 10.2.1-6) 10.2.1 20210110\n\t\t\tCopyright (C) 2020 Free Software Foundation, Inc.\n\t\t\tThis is free software; see the source for copying conditions.  There is NO\n\t\t\twarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.`,\n\t\t},\n\t\t{\n\t\t\tCase:           \"GNU Fortran 11.4.0 Ubuntu\",\n\t\t\tExpectedString: \"11.4.0\",\n\t\t\tVersion: `GNU Fortran (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0\n\t\t\tCopyright (C) 2021 Free Software Foundation, Inc.\n\t\t\tThis is free software; see the source for copying conditions.  There is NO\n\t\t\twarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.`,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"gfortran\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.f\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tf := &Fortran{}\n\t\tf.Init(props, env)\n\t\tassert.True(t, f.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, f.Template(), f), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/fossil.go",
    "content": "package segments\n\nimport \"strings\"\n\n// FossilStatus represents part of the status of a Svn repository\ntype FossilStatus struct {\n\tScmStatus\n}\n\nfunc (s *FossilStatus) add(code string) {\n\tswitch code {\n\tcase \"CONFLICT\":\n\t\ts.Conflicted++\n\tcase \"DELETED\", \"MISSING\":\n\t\ts.Deleted++\n\tcase \"ADDED\", \"ADDED_BY_INTEGRATE\", \"ADDED_BY_MERGE\":\n\t\ts.Added++\n\tcase \"EDITED\", \"UPDATED\", \"UPDATED_BY_INTEGRATE\", \"UPDATED_BY_MERGE\", \"CHANGED\":\n\t\ts.Modified++\n\tcase \"RENAMED\":\n\t\ts.Moved++\n\t}\n}\n\nconst (\n\tFOSSILCOMMAND = \"fossil\"\n)\n\ntype Fossil struct {\n\tStatus *FossilStatus\n\tBranch string\n\tScm\n}\n\nfunc (f *Fossil) Template() string {\n\treturn \" \\ue725 {{.Branch}} {{.Status.String}} \"\n}\n\nfunc (f *Fossil) Enabled() bool {\n\tif !f.hasCommand(FOSSILCOMMAND) {\n\t\treturn false\n\t}\n\n\t// run fossil command\n\toutput, err := f.env.RunCommand(f.command, \"status\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tf.Status = &FossilStatus{}\n\tlines := strings.SplitSeq(output, \"\\n\")\n\n\tfor line := range lines {\n\t\tkey, value, found := strings.Cut(line, \" \")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\tswitch key {\n\t\tcase \"tags:\":\n\t\t\tf.Branch = strings.TrimSpace(value)\n\t\tdefault:\n\t\t\tf.Status.add(key)\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/fossil_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFossilStatus(t *testing.T) {\n\tcases := []struct {\n\t\tOutputError      error\n\t\tCase             string\n\t\tOutput           string\n\t\tExpectedStatus   string\n\t\tExpectedBranch   string\n\t\tHasCommand       bool\n\t\tExpectedDisabled bool\n\t}{\n\t\t{\n\t\t\tCase:             \"not installed\",\n\t\t\tHasCommand:       false,\n\t\t\tExpectedDisabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:             \"command error\",\n\t\t\tHasCommand:       true,\n\t\t\tOutputError:      fmt.Errorf(\"error\"),\n\t\t\tExpectedDisabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:       \"default status\",\n\t\t\tHasCommand: true,\n\t\t\tOutput: `\n\t\t\trepository:   /Users/jan/Downloads/myclone.fossil\n\t\t\tlocal-root:   /Users/jan/Projects/fossil/\n\t\t\tconfig-db:    /Users/jan/.config/fossil.db\n\t\t\tcheckout:     0fabc4f3566c7e7d9e528b17253de42e14dd5c7b 2022-06-05 04:06:17 UTC\n\t\t\tparent:       e8a051e6a943a26c9c33a30df8ceda069c06c174 2022-06-04 23:09:02 UTC\n\t\t\ttags:         trunk\n\t\t\tcomment:      In the /setup_skin page, add a mention of/link to /skins, per request in the forum. (user: stephan)\n\t\t\tCONFLICT             test.tst\n\t\t\tDELETED\t             test.tst\n\t\t\tMISSING              test.tst\n\t\t\tADDED                test.tst\n\t\t\tADDED_BY_INTEGRATE   test.tst\n\t\t\tADDED_BY_MERGE       test.tst\n\t\t\tEDITED               auto.def\n\t\t\tUPDATED              test.tst\n\t\t\tUPDATED_BY_INTEGRATE test.tst\n\t\t\tUPDATED_BY_MERGE \t test.tst\n\t\t\tCHANGED \t         test.tst\n\t\t\tRENAMED \t\t     test.tst\n\t\t\t`,\n\t\t\tExpectedBranch: \"trunk\",\n\t\t\tExpectedStatus: \"+3 ~5 -2 >1 !1\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(\"unix\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"HasCommand\", FOSSILCOMMAND).Return(tc.HasCommand)\n\t\tenv.On(\"RunCommand\", FOSSILCOMMAND, []string{\"status\"}).Return(strings.ReplaceAll(tc.Output, \"\\t\", \"\"), tc.OutputError)\n\n\t\tf := &Fossil{}\n\t\tf.Init(options.Map{}, env)\n\n\t\tgot := f.Enabled()\n\n\t\tassert.Equal(t, !tc.ExpectedDisabled, got, tc.Case)\n\t\tif tc.ExpectedDisabled {\n\t\t\tcontinue\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedStatus, f.Status.String(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBranch, f.Branch, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/gcp.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"path\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\n\t\"gopkg.in/ini.v1\"\n)\n\nconst (\n\tGCPNOACTIVECONFIG = \"NO ACTIVE CONFIG FOUND\"\n)\n\ntype Gcp struct {\n\tBase\n\n\tAccount      string\n\tProject      string\n\tRegion       string\n\tActiveConfig string\n}\n\nfunc (g *Gcp) Template() string {\n\treturn \" {{ .Project }} \"\n}\n\nfunc (g *Gcp) Enabled() bool {\n\tcfgDir := g.getConfigDirectory()\n\tcfgName, err := g.getActiveConfig(cfgDir)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tg.ActiveConfig = cfgName\n\tcfgPath := path.Join(cfgDir, \"configurations\", \"config_\"+cfgName)\n\tcfg := g.env.FileContent(cfgPath)\n\n\tif cfg == \"\" {\n\t\tlog.Error(errors.New(\"config file is empty\"))\n\t\treturn false\n\t}\n\n\tdata, err := ini.Load([]byte(cfg))\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tg.Project = data.Section(\"core\").Key(\"project\").String()\n\tg.Account = data.Section(\"core\").Key(\"account\").String()\n\tg.Region = data.Section(\"compute\").Key(\"region\").String()\n\n\treturn true\n}\n\nfunc (g *Gcp) getActiveConfig(cfgDir string) (string, error) {\n\tactiveCfg := g.env.Getenv(\"CLOUDSDK_ACTIVE_CONFIG_NAME\")\n\tif len(activeCfg) != 0 {\n\t\treturn activeCfg, nil\n\t}\n\n\tap := path.Join(cfgDir, \"active_config\")\n\tactiveCfg = g.env.FileContent(ap)\n\tif activeCfg == \"\" {\n\t\treturn \"\", errors.New(GCPNOACTIVECONFIG)\n\t}\n\n\treturn activeCfg, nil\n}\n\nfunc (g *Gcp) getConfigDirectory() string {\n\tcfgDir := g.env.Getenv(\"CLOUDSDK_CONFIG\")\n\tif len(cfgDir) != 0 {\n\t\treturn cfgDir\n\t}\n\n\tif g.env.GOOS() == runtime.WINDOWS {\n\t\treturn path.Join(g.env.Getenv(\"APPDATA\"), \"gcloud\")\n\t}\n\n\treturn path.Join(g.env.Home(), \".config\", \"gcloud\")\n}\n"
  },
  {
    "path": "src/segments/gcp_test.go",
    "content": "package segments\n\nimport (\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGcpSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tCfgData         string\n\t\tActiveConfig    string\n\t\tEnvActiveConfig string\n\t\tExpectedString  string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"happy path\",\n\t\t\tExpectedEnabled: true,\n\t\t\tActiveConfig:    \"production\",\n\t\t\tCfgData: `\n\t\t\t[core]\n\t\t\taccount = test@example.com\n\t\t\tproject = test-test-test\n\n\t\t\t[compute]\n\t\t\tregion = europe-test1\n\t\t\t`,\n\t\t\tExpectedString: \"test-test-test :: europe-test1 :: test@example.com\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"no active config\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"empty config\",\n\t\t\tActiveConfig:    \"production\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"bad config\",\n\t\t\tActiveConfig:    \"production\",\n\t\t\tCfgData:         \"{bad}\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"use CLOUDSDK_ACTIVE_CONFIG_NAME\",\n\t\t\tEnvActiveConfig: \"myconfig\",\n\t\t\tExpectedEnabled: true,\n\t\t\tCfgData: `\n\t\t\t[core]\n\t\t\taccount = user@example.com\n\t\t\tproject = cloud-proj\n\n\t\t\t[compute]\n\t\t\tregion = us-west1\n\t\t\t`,\n\t\t\tExpectedString: \"cloud-proj :: us-west1 :: user@example.com\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"CLOUDSDK_CONFIG\").Return(\"config\")\n\t\tenv.On(\"Getenv\", \"CLOUDSDK_ACTIVE_CONFIG_NAME\").Return(tc.EnvActiveConfig)\n\n\t\t// Only use fallback file if env var is not set\n\t\tif tc.EnvActiveConfig == \"\" {\n\t\t\tfcPath := path.Join(\"config\", \"active_config\")\n\t\t\tenv.On(\"FileContent\", fcPath).Return(tc.ActiveConfig)\n\t\t}\n\n\t\t// Resolve active config name\n\t\tactiveConfig := tc.EnvActiveConfig\n\t\tif activeConfig == \"\" {\n\t\t\tactiveConfig = tc.ActiveConfig\n\t\t}\n\n\t\tcfgpath := path.Join(\"config\", \"configurations\", \"config_\"+activeConfig)\n\t\tenv.On(\"FileContent\", cfgpath).Return(tc.CfgData)\n\n\t\tg := &Gcp{}\n\t\tg.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, g.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, \"{{.Project}} :: {{.Region}} :: {{.Account}}\", g), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestGetConfigDirectory(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tGOOS           string\n\t\tHome           string\n\t\tAppData        string\n\t\tCloudSDKConfig string\n\t\tExpected       string\n\t}{\n\t\t{\n\t\t\tCase:           \"CLOUDSDK_CONFIG\",\n\t\t\tCloudSDKConfig: \"/Users/posh/.config/gcloud\",\n\t\t\tExpected:       \"/Users/posh/.config/gcloud\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Windows\",\n\t\t\tGOOS:     runtime.WINDOWS,\n\t\t\tAppData:  \"/Users/posh/.config\",\n\t\t\tExpected: \"/Users/posh/.config/gcloud\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"default\",\n\t\t\tHome:     \"/Users/posh2/\",\n\t\t\tExpected: \"/Users/posh2/.config/gcloud\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"CLOUDSDK_CONFIG\").Return(tc.CloudSDKConfig)\n\t\tenv.On(\"Getenv\", \"APPDATA\").Return(tc.AppData)\n\t\tenv.On(\"Home\").Return(tc.Home)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\n\t\tg := &Gcp{}\n\t\tg.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.Expected, g.getConfigDirectory(), tc.Case)\n\t}\n}\n\nfunc TestGetActiveConfig(t *testing.T) {\n\tcases := []struct {\n\t\tCase                    string\n\t\tEnvActiveConfigName     string\n\t\tFileActiveConfigContent string\n\t\tExpectedString          string\n\t\tExpectedError           string\n\t}{\n\t\t{\n\t\t\tCase:                \"CLOUDSDK_ACTIVE_CONFIG_NAME set\",\n\t\t\tEnvActiveConfigName: \"envconfig\",\n\t\t\tExpectedString:      \"envconfig\",\n\t\t},\n\t\t{\n\t\t\tCase:                    \"Fallback to file content\",\n\t\t\tFileActiveConfigContent: \"fileconfig\",\n\t\t\tExpectedString:          \"fileconfig\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"No config anywhere\",\n\t\t\tExpectedError: GCPNOACTIVECONFIG,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"CLOUDSDK_ACTIVE_CONFIG_NAME\").Return(tc.EnvActiveConfigName)\n\n\t\t// If env var not set, mock file fallback\n\t\tif tc.EnvActiveConfigName == \"\" {\n\t\t\tenv.On(\"FileContent\", path.Join(\"\", \"active_config\")).Return(tc.FileActiveConfigContent)\n\t\t}\n\n\t\tg := &Gcp{}\n\t\tg.Init(options.Map{}, env)\n\n\t\tgot, err := g.getActiveConfig(\"\")\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t\tif len(tc.ExpectedError) > 0 {\n\t\t\tassert.EqualError(t, err, tc.ExpectedError, tc.Case)\n\t\t} else {\n\t\t\tassert.NoError(t, err, tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/git.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\turl2 \"net/url\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"gopkg.in/ini.v1\"\n)\n\ntype Commit struct {\n\tTimestamp time.Time\n\tAuthor    *User\n\tCommitter *User\n\tRefs      *Refs\n\tSubject   string\n\tSha       string\n}\n\ntype Refs struct {\n\tHeads   []string\n\tTags    []string\n\tRemotes []string\n}\n\ntype User struct {\n\tName  string\n\tEmail string\n}\n\n// GitStatus represents part of the status of a git repository\ntype GitStatus struct {\n\tScmStatus\n}\n\nfunc (s *GitStatus) add(code string) {\n\tswitch code {\n\tcase \".\":\n\t\treturn\n\tcase \"D\":\n\t\ts.Deleted++\n\tcase \"A\":\n\t\ts.Added++\n\tcase \"?\":\n\t\ts.Untracked++\n\tcase \"U\", \"AA\":\n\t\ts.Unmerged++\n\tcase \"M\", \"R\", \"C\", \"m\":\n\t\ts.Modified++\n\t}\n}\n\nconst (\n\t// FetchStatus fetches the status of the repository\n\tFetchStatus options.Option = \"fetch_status\"\n\t// FetchPushStatus fetches the push-remote status\n\tFetchPushStatus options.Option = \"fetch_push_status\"\n\t// IgnoreStatus allows to ignore certain repo's for status information\n\tIgnoreStatus options.Option = \"ignore_status\"\n\t// FetchUpstreamIcon fetches the upstream icon\n\tFetchUpstreamIcon options.Option = \"fetch_upstream_icon\"\n\t// FetchBareInfo fetches the bare repo status\n\tFetchBareInfo options.Option = \"fetch_bare_info\"\n\t// FetchUser fetches the current user for the repo\n\tFetchUser options.Option = \"fetch_user\"\n\t// UntrackedModes list the optional untracked files mode per repo\n\tUntrackedModes options.Option = \"untracked_modes\"\n\t// IgnoreSubmodules list the optional ignore-submodules mode per repo\n\tIgnoreSubmodules options.Option = \"ignore_submodules\"\n\t// MappedBranches allows overriding certain branches with an icon/text\n\tMappedBranches options.Option = \"mapped_branches\"\n\t// DisableWithJJ disables the git segment when there's a .jj directory in the parent file path\n\tDisableWithJJ options.Option = \"disable_with_jj\"\n\n\t// BranchIcon the icon to use as branch indicator\n\tBranchIcon options.Option = \"branch_icon\"\n\t// BranchIdenticalIcon the icon to display when the remote and local branch are identical\n\tBranchIdenticalIcon options.Option = \"branch_identical_icon\"\n\t// BranchAheadIcon the icon to display when the local branch is ahead of the remote\n\tBranchAheadIcon options.Option = \"branch_ahead_icon\"\n\t// BranchBehindIcon the icon to display when the local branch is behind the remote\n\tBranchBehindIcon options.Option = \"branch_behind_icon\"\n\t// BranchGoneIcon the icon to use when ther's no remote\n\tBranchGoneIcon options.Option = \"branch_gone_icon\"\n\t// RebaseIcon shows before the rebase context\n\tRebaseIcon options.Option = \"rebase_icon\"\n\t// CherryPickIcon shows before the cherry-pick context\n\tCherryPickIcon options.Option = \"cherry_pick_icon\"\n\t// RevertIcon shows before the revert context\n\tRevertIcon options.Option = \"revert_icon\"\n\t// CommitIcon shows before the detached context\n\tCommitIcon options.Option = \"commit_icon\"\n\t// NoCommitsIcon shows when there are no commits in the repo yet\n\tNoCommitsIcon options.Option = \"no_commits_icon\"\n\t// TagIcon shows before the tag context\n\tTagIcon options.Option = \"tag_icon\"\n\t// MergeIcon shows before the merge context\n\tMergeIcon options.Option = \"merge_icon\"\n\t// UpstreamIcons allows to add custom upstream icons\n\tUpstreamIcons options.Option = \"upstream_icons\"\n\t// GithubIcon shows when upstream is github\n\tGithubIcon options.Option = \"github_icon\"\n\t// BitbucketIcon shows  when upstream is bitbucket\n\tBitbucketIcon options.Option = \"bitbucket_icon\"\n\t// AzureDevOpsIcon shows  when upstream is azure devops\n\tAzureDevOpsIcon options.Option = \"azure_devops_icon\"\n\t// CodeCommit shows  when upstream is aws codecommit\n\tCodeCommit options.Option = \"codecommit_icon\"\n\t// CodebergIcon shows when upstream is codeberg\n\tCodebergIcon options.Option = \"codeberg_icon\"\n\t// GitlabIcon shows when upstream is gitlab\n\tGitlabIcon options.Option = \"gitlab_icon\"\n\t// GitIcon shows when the upstream can't be identified\n\tGitIcon options.Option = \"git_icon\"\n\n\tDETACHED     = \"(detached)\"\n\tBRANCHPREFIX = \"ref: refs/heads/\"\n\tGITCOMMAND   = \"git\"\n\n\ttrueStr = \"true\"\n\torigin  = \"origin\"\n)\n\ntype Rebase struct {\n\tHEAD    string\n\tOnto    string\n\tCurrent int\n\tTotal   int\n}\n\ntype Git struct {\n\tconfigErr      error\n\tconfig         *ini.File\n\tWorking        *GitStatus\n\tStaging        *GitStatus\n\tcommit         *Commit\n\tRebase         *Rebase\n\tUser           *User\n\tShortHash      string\n\tHash           string\n\tBranchStatus   string\n\tHEAD           string\n\tUpstreamIcon   string\n\tUpstreamURL    string\n\tRef            string\n\tRawUpstreamURL string\n\tScm\n\tstashCount    int\n\tAhead         int\n\tPushAhead     int\n\tPushBehind    int\n\tBehind        int\n\tworktreeCount int\n\tconfigOnce    sync.Once\n\tIsWorkTree    bool\n\tMerge         bool\n\tCherryPick    bool\n\tRevert        bool\n\tposhgit       bool\n\tDetached      bool\n\tIsBare        bool\n\tUpstreamGone  bool\n}\n\nfunc (g *Git) Template() string {\n\treturn \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }} \" //nolint: lll\n}\n\nfunc (g *Git) Enabled() bool {\n\tg.User = &User{}\n\tg.Working = &GitStatus{}\n\tg.Staging = &GitStatus{}\n\n\tif !g.shouldDisplay() {\n\t\treturn false\n\t}\n\n\tfetchUser := g.options.Bool(FetchUser, false)\n\tif fetchUser {\n\t\tg.setUser()\n\t}\n\n\tg.RepoName = g.repoName()\n\n\tif g.IsBare {\n\t\tg.getBareRepoInfo()\n\t\treturn true\n\t}\n\n\tsource := g.options.String(Source, Cli)\n\tif source == Pwsh && g.hasPoshGitStatus() {\n\t\treturn true\n\t}\n\n\tdisplayStatus := g.options.Bool(FetchStatus, false)\n\tif displayStatus && g.shouldIgnoreStatus() {\n\t\tdisplayStatus = false\n\t}\n\n\tif displayStatus {\n\t\tg.setStatus()\n\t\tg.setHEADStatus()\n\t\tg.setBranchStatus()\n\t\tg.setPushStatus()\n\t} else {\n\t\tg.updateHEADReference()\n\t}\n\n\tif g.options.Bool(FetchUpstreamIcon, false) {\n\t\tg.UpstreamIcon = g.getUpstreamIcon()\n\t}\n\n\treturn true\n}\n\nfunc (g *Git) CacheKey() (string, bool) {\n\tdir, err := g.env.HasParentFilePath(\".git\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\tif !g.isRepo(dir) {\n\t\treturn \"\", false\n\t}\n\n\tref := g.fileContent(g.mainSCMDir, \"HEAD\")\n\tref = strings.Replace(ref, \"ref: refs/heads/\", \"\", 1)\n\n\t// Use the repo clone in the cache key so the mapped path is consistent\n\t// for primary and worktree repos.\n\treturn fmt.Sprintf(\"%s@%s\", dir.Path, ref), true\n}\n\nfunc (g *Git) Commit() *Commit {\n\tif g.commit != nil {\n\t\treturn g.commit\n\t}\n\n\tg.commit = &Commit{\n\t\tAuthor:    &User{},\n\t\tCommitter: &User{},\n\t\tRefs:      &Refs{},\n\t}\n\n\tcommitBody := g.getGitCommandOutput(\"log\", \"-1\", \"--pretty=format:an:%an%nae:%ae%ncn:%cn%nce:%ce%nat:%at%nsu:%s%nha:%H%nrf:%D\", \"--decorate=full\")\n\tsplitted := strings.SplitSeq(strings.TrimSpace(commitBody), \"\\n\")\n\tfor line := range splitted {\n\t\tline = strings.TrimSpace(line)\n\t\tif len(line) <= 3 {\n\t\t\tcontinue\n\t\t}\n\t\tanchor := line[:3]\n\t\tline = line[3:]\n\t\tswitch anchor {\n\t\tcase \"an:\":\n\t\t\tg.commit.Author.Name = line\n\t\tcase \"ae:\":\n\t\t\tg.commit.Author.Email = line\n\t\tcase \"cn:\":\n\t\t\tg.commit.Committer.Name = line\n\t\tcase \"ce:\":\n\t\t\tg.commit.Committer.Email = line\n\t\tcase \"at:\":\n\t\t\tif t, err := strconv.ParseInt(line, 10, 64); err == nil {\n\t\t\t\tg.commit.Timestamp = time.Unix(t, 0)\n\t\t\t}\n\t\tcase \"su:\":\n\t\t\tg.commit.Subject = line\n\t\tcase \"ha:\":\n\t\t\tg.commit.Sha = line\n\t\tcase \"rf:\":\n\t\t\trefs := strings.SplitSeq(line, \", \")\n\t\t\tfor ref := range refs {\n\t\t\t\tref = strings.TrimSpace(ref)\n\t\t\t\tswitch {\n\t\t\t\tcase strings.HasSuffix(ref, \"HEAD\"):\n\t\t\t\t\tcontinue\n\t\t\t\tcase strings.HasPrefix(ref, \"tag: refs/tags/\"):\n\t\t\t\t\tg.commit.Refs.Tags = append(g.commit.Refs.Tags, strings.TrimPrefix(ref, \"tag: refs/tags/\"))\n\t\t\t\tcase strings.HasPrefix(ref, \"refs/remotes/\"):\n\t\t\t\t\tg.commit.Refs.Remotes = append(g.commit.Refs.Remotes, strings.TrimPrefix(ref, \"refs/remotes/\"))\n\t\t\t\tcase strings.HasPrefix(ref, \"HEAD -> refs/heads/\"):\n\t\t\t\t\tg.commit.Refs.Heads = append(g.commit.Refs.Heads, strings.TrimPrefix(ref, \"HEAD -> refs/heads/\"))\n\t\t\t\tcase strings.HasPrefix(ref, \"refs/heads/\"):\n\t\t\t\t\tg.commit.Refs.Heads = append(g.commit.Refs.Heads, strings.TrimPrefix(ref, \"refs/heads/\"))\n\t\t\t\tdefault:\n\t\t\t\t\tg.commit.Refs.Heads = append(g.commit.Refs.Heads, ref)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn g.commit\n}\n\nfunc (g *Git) StashCount() int {\n\tif g.poshgit || g.stashCount != 0 {\n\t\treturn g.stashCount\n\t}\n\n\tstashContent := g.fileContent(g.scmDir, \"logs/refs/stash\")\n\tif stashContent == \"\" {\n\t\treturn 0\n\t}\n\n\tg.stashCount = strings.Count(stashContent, \"\\n\") + 1 // +1: fileContent() trims\n\treturn g.stashCount\n}\n\nfunc (g *Git) Kraken() string {\n\troot := g.getGitCommandOutput(\"rev-list\", \"--max-parents=0\", \"HEAD\")\n\troot, _, _ = strings.Cut(root, \"\\n\")\n\n\tif g.RawUpstreamURL == \"\" {\n\t\tif g.Upstream == \"\" {\n\t\t\tg.Upstream = origin\n\t\t}\n\t\tg.RawUpstreamURL = g.getRemoteURL()\n\t}\n\n\tif g.Hash == \"\" {\n\t\tg.Hash = g.getGitCommandOutput(\"rev-parse\", \"HEAD\")\n\t}\n\n\treturn fmt.Sprintf(\"gitkraken://repolink/%s/commit/%s?url=%s\", root, g.Hash, url2.QueryEscape(g.RawUpstreamURL))\n}\n\nfunc (g *Git) LatestTag() string {\n\treturn g.getGitCommandOutput(\"describe\", \"--tags\", \"--abbrev=0\")\n}\n\nfunc (g *Git) shouldDisplay() bool {\n\t// Check if disable_with_jj is enabled and .jj directory exists\n\tif g.options.Bool(DisableWithJJ, false) {\n\t\tif _, err := g.env.HasParentFilePath(\".jj\", false); err == nil {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tgitdir, err := g.env.HasParentFilePath(\".git\", true)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tif g.options.Bool(FetchBareInfo, false) {\n\t\tg.IsBare = g.isBareRepo(gitdir)\n\t}\n\n\tif !g.hasCommand(GITCOMMAND) {\n\t\treturn false\n\t}\n\n\treturn g.isRepo(gitdir)\n}\n\nfunc (g *Git) isRepo(gitdir *runtime.FileInfo) bool {\n\tg.setDir(gitdir.Path)\n\n\tif !gitdir.IsDir {\n\t\tif g.hasWorktree(gitdir) {\n\t\t\tg.repoRootDir = g.convertToWindowsPath(g.repoRootDir)\n\t\t\treturn true\n\t\t}\n\n\t\treturn false\n\t}\n\n\tg.mainSCMDir = gitdir.Path\n\tg.scmDir = gitdir.Path\n\t// convert the worktree file path to a windows one when in a WSL shared folder\n\tg.repoRootDir = strings.TrimSuffix(g.convertToWindowsPath(gitdir.Path), \"/.git\")\n\treturn true\n}\n\nfunc (g *Git) setUser() {\n\tg.User.Name = g.getGitCommandOutput(\"config\", \"user.name\")\n\tg.User.Email = g.getGitCommandOutput(\"config\", \"user.email\")\n}\n\nfunc (g *Git) isBareRepo(gitDir *runtime.FileInfo) bool {\n\tdefer log.Trace(time.Now())\n\n\tif gitDir.IsDir {\n\t\tg.mainSCMDir = gitDir.Path\n\t} else {\n\t\tcontent := g.fileContent(gitDir.ParentFolder, \".git\")\n\t\tdir := strings.TrimPrefix(content, \"gitdir: \")\n\t\tg.mainSCMDir = filepath.Join(gitDir.ParentFolder, dir)\n\t}\n\n\tcfg, err := g.getGitConfig()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tcoreSection := cfg.Section(\"core\")\n\tif coreSection == nil {\n\t\tlog.Debug(\"Git core section not found, not a bare repo\")\n\t\treturn false\n\t}\n\n\tbare := coreSection.Key(\"bare\").String()\n\n\treturn bare == trueStr\n}\n\nfunc (g *Git) getBareRepoInfo() {\n\thead := g.fileContent(g.mainSCMDir, \"HEAD\")\n\tbranchIcon := g.options.String(BranchIcon, \"\\uE0A0\")\n\tg.Ref = strings.Replace(head, \"ref: refs/heads/\", \"\", 1)\n\tg.HEAD = fmt.Sprintf(\"%s%s\", branchIcon, g.formatBranch(g.Ref))\n\tif !g.options.Bool(FetchUpstreamIcon, false) {\n\t\treturn\n\t}\n\n\tg.Upstream = g.getGitCommandOutput(\"remote\")\n\tif len(g.Upstream) != 0 {\n\t\tg.UpstreamIcon = g.getUpstreamIcon()\n\t}\n}\n\nfunc (g *Git) setDir(dir string) {\n\tdir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD\n\tif g.env.GOOS() == runtime.WINDOWS {\n\t\tg.Dir = strings.TrimSuffix(dir, `\\.git`)\n\t\treturn\n\t}\n\n\tg.Dir = strings.TrimSuffix(dir, \"/.git\")\n}\n\nfunc (g *Git) hasWorktree(gitdir *runtime.FileInfo) bool {\n\tg.scmDir = gitdir.Path\n\tcontent := g.env.FileContent(gitdir.Path)\n\tcontent = strings.Trim(content, \" \\r\\n\")\n\tmatches := regex.FindNamedRegexMatch(`^gitdir: (?P<dir>.*)$`, content)\n\n\tif len(matches) == 0 {\n\t\tlog.Debug(\"no matches found, directory isn't a worktree\")\n\t\treturn false\n\t}\n\n\t// if we open a worktree file in a WSL shared folder, we have to convert it back\n\t// to the mounted path\n\tg.mainSCMDir = g.convertToLinuxPath(matches[\"dir\"])\n\n\t// in worktrees, the path looks like this: gitdir: path/.git/worktrees/branch\n\t// scmDir needs to become path/.git\n\t// repoRootDir needs to become path\n\tworktreeIndex := strings.LastIndex(g.mainSCMDir, \"/worktrees/\")\n\n\t// in submodules, the path looks like this: gitdir: ../.git/modules/test-submodule\n\t// we need the parent folder to detect where the real .git folder is\n\tif strings.Contains(g.mainSCMDir, \"/modules/\") {\n\t\tg.scmDir = resolveGitPath(gitdir.ParentFolder, g.mainSCMDir)\n\t\t// this might be both a worktree and a submodule, where the path would look like\n\t\t// this: path/.git/modules/module/path/worktrees/location. We cannot distinguish\n\t\t// between worktree and a module path containing the word 'worktree,' however.\n\t\tworktreeIndex = strings.LastIndex(g.scmDir, \"/worktrees/\")\n\t\tif worktreeIndex > -1 && g.env.HasFilesInDir(g.scmDir, \"gitdir\") {\n\t\t\tgitDir := filepath.Join(g.scmDir, \"gitdir\")\n\t\t\trealGitFolder := g.env.FileContent(gitDir)\n\t\t\tg.repoRootDir = strings.TrimSuffix(realGitFolder, \".git\\n\")\n\t\t\t// resolve relative paths (worktree.useRelativePaths = true)\n\t\t\tg.repoRootDir = resolveGitPath(g.scmDir, g.repoRootDir)\n\t\t\tg.scmDir = g.scmDir[:worktreeIndex]\n\t\t\tg.mainSCMDir = g.scmDir\n\t\t\tg.IsWorkTree = true\n\t\t\treturn true\n\t\t}\n\n\t\tg.repoRootDir = g.scmDir\n\t\tg.mainSCMDir = g.scmDir\n\t\treturn true\n\t}\n\n\t// convert to absolute path for worktrees only\n\tif strings.HasPrefix(g.mainSCMDir, \"..\") {\n\t\tg.mainSCMDir = filepath.Join(gitdir.ParentFolder, g.mainSCMDir)\n\t}\n\n\tif worktreeIndex > -1 {\n\t\tgitDir := filepath.Join(g.mainSCMDir, \"gitdir\")\n\t\tg.scmDir = g.mainSCMDir[:worktreeIndex]\n\t\tgitDirContent := g.env.FileContent(gitDir)\n\t\tg.repoRootDir = strings.TrimSuffix(gitDirContent, \".git\\n\")\n\t\t// resolve relative paths (worktree.useRelativePaths = true)\n\t\tg.repoRootDir = resolveGitPath(g.mainSCMDir, g.repoRootDir)\n\t\tg.IsWorkTree = true\n\t\treturn true\n\t}\n\n\t// check for separate git folder(--separate-git-dir)\n\t// check if the folder contains a HEAD file\n\tif g.env.HasFilesInDir(g.mainSCMDir, \"HEAD\") {\n\t\tgitFolder := strings.TrimSuffix(g.scmDir, \".git\")\n\t\tg.scmDir = g.mainSCMDir\n\t\tg.mainSCMDir = gitFolder\n\t\tg.repoRootDir = gitFolder\n\t\treturn true\n\t}\n\n\treturn false\n}\n\nfunc (g *Git) shouldIgnoreStatus() bool {\n\tlist := g.options.StringArray(IgnoreStatus, []string{})\n\treturn g.env.DirMatchesOneOf(g.repoRootDir, list)\n}\n\nfunc (g *Git) setBranchStatus() {\n\tgetBranchStatus := func() string {\n\t\tif g.Ahead > 0 && g.Behind > 0 {\n\t\t\treturn fmt.Sprintf(\"%s%d %s%d\", g.options.String(BranchAheadIcon, \"\\u2191\"), g.Ahead, g.options.String(BranchBehindIcon, \"\\u2193\"), g.Behind)\n\t\t}\n\t\tif g.Ahead > 0 {\n\t\t\treturn fmt.Sprintf(\"%s%d\", g.options.String(BranchAheadIcon, \"\\u2191\"), g.Ahead)\n\t\t}\n\t\tif g.Behind > 0 {\n\t\t\treturn fmt.Sprintf(\"%s%d\", g.options.String(BranchBehindIcon, \"\\u2193\"), g.Behind)\n\t\t}\n\t\tif g.UpstreamGone {\n\t\t\treturn g.options.String(BranchGoneIcon, \"\\u2262\")\n\t\t}\n\t\tif g.Behind == 0 && g.Ahead == 0 && g.Upstream != \"\" {\n\t\t\treturn g.options.String(BranchIdenticalIcon, \"\\u2261\")\n\t\t}\n\t\treturn \"\"\n\t}\n\tg.BranchStatus = getBranchStatus()\n}\n\nfunc (g *Git) setPushStatus() {\n\tif !g.options.Bool(FetchPushStatus, false) {\n\t\treturn\n\t}\n\n\tif g.Ref == \"\" || g.Ref == DETACHED {\n\t\treturn\n\t}\n\n\tpushRemote := g.getPushRemote()\n\tif pushRemote == \"\" {\n\t\treturn\n\t}\n\n\tahead := g.getGitCommandOutput(\"rev-list\", \"--count\", pushRemote+\"..HEAD\")\n\tif ahead != \"\" {\n\t\tg.PushAhead, _ = strconv.Atoi(strings.TrimSpace(ahead))\n\t}\n\n\tbehind := g.getGitCommandOutput(\"rev-list\", \"--count\", \"HEAD..\"+pushRemote)\n\tif behind != \"\" {\n\t\tg.PushBehind, _ = strconv.Atoi(strings.TrimSpace(behind))\n\t}\n}\n\nfunc (g *Git) getPushRemote() string {\n\tupstream := g.Upstream\n\tif idx := strings.Index(upstream, \"/\"); idx != -1 {\n\t\tupstream = upstream[:idx]\n\t}\n\n\tif upstream == \"\" {\n\t\tupstream = origin\n\t}\n\n\tbranch := g.Ref\n\tif branch == \"\" {\n\t\treturn \"\"\n\t}\n\n\tcfg, err := g.getGitConfig()\n\tif err != nil {\n\t\tpushRemote := g.getGitCommandOutput(\"config\", \"--get\", \"remote.pushDefault\")\n\t\tif pushRemote == \"\" {\n\t\t\tpushRemote = upstream\n\t\t}\n\n\t\treturn strings.TrimSpace(pushRemote) + \"/\" + branch\n\t}\n\n\tsectionName := fmt.Sprintf(`branch \"%s\"`, branch)\n\tsection := cfg.Section(sectionName)\n\tpushRemote := section.Key(\"pushRemote\").String()\n\tif pushRemote == \"\" {\n\t\tpushRemote = cfg.Section(\"remote\").Key(\"pushDefault\").String()\n\t}\n\n\tif pushRemote == \"\" {\n\t\tpushRemote = upstream\n\t}\n\n\treturn pushRemote + \"/\" + branch\n}\n\nfunc (g *Git) getGitConfig() (*ini.File, error) {\n\tg.configOnce.Do(func() {\n\t\tconfigData := g.fileContent(g.mainSCMDir, \"config\")\n\t\tif configData == \"\" {\n\t\t\tlog.Debug(\"git config file not found\")\n\t\t\tg.configErr = fmt.Errorf(\"git config file not found\")\n\t\t\treturn\n\t\t}\n\n\t\t// ini.Load expects []byte to parse content, not a file path\n\t\tcfg, err := ini.Load([]byte(configData))\n\t\tif err != nil {\n\t\t\tg.configErr = err\n\t\t\treturn\n\t\t}\n\n\t\tg.config = cfg\n\t})\n\n\treturn g.config, g.configErr\n}\n\nfunc (g *Git) cleanUpstreamURL(url string) string {\n\t// Azure DevOps\n\tif strings.Contains(url, \"dev.azure.com\") {\n\t\tmatch := regex.FindNamedRegexMatch(`^.*@(ssh.)?dev\\.azure\\.com(:v3)?/(?P<ORGANIZATION>[A-Za-z0-9_-]+)/(?P<PROJECT>[A-Za-z0-9_-]+)/(_git/)?(?P<REPOSITORY>[A-Za-z0-9_-]+)$`, url)\n\t\tif len(match) == 4 {\n\t\t\treturn fmt.Sprintf(\"https://dev.azure.com/%s/%s/_git/%s\", match[\"ORGANIZATION\"], match[\"PROJECT\"], match[\"REPOSITORY\"])\n\t\t}\n\t}\n\n\tif strings.HasPrefix(url, \"http\") {\n\t\treturn url\n\t}\n\n\t// /path/to/repo.git/\n\tmatch := regex.FindNamedRegexMatch(`^(?P<URL>[a-z0-9./]+)$`, url)\n\tif len(match) != 0 {\n\t\turl := strings.Trim(match[\"URL\"], \"/\")\n\t\turl = strings.TrimSuffix(url, \".git\")\n\t\treturn fmt.Sprintf(\"https://%s\", strings.TrimPrefix(url, \"/\"))\n\t}\n\n\t// ssh://user@host.xz:1234/path/to/repo.git/\n\tmatch = regex.FindNamedRegexMatch(`(ssh|ftp|git|rsync)://(.*@)?(?P<URL>[a-z0-9.-]+)(:[0-9]{1,5})?/(?P<PATH>.*).git`, url)\n\tif len(match) == 0 {\n\t\t// host.xz:/path/to/repo.git/\n\t\tmatch = regex.FindNamedRegexMatch(`^(?P<URL>[a-z0-9.-]+):(?P<PATH>[\\w.\\-~/@]+)$`, url)\n\t}\n\n\tif len(match) != 0 {\n\t\trepoPath := strings.Trim(match[\"PATH\"], \"/\")\n\t\trepoPath = strings.TrimSuffix(repoPath, \".git\")\n\t\treturn fmt.Sprintf(\"https://%s/%s\", match[\"URL\"], repoPath)\n\t}\n\n\t// codecommit::region-identifier-id://repo-name\n\tmatch = regex.FindNamedRegexMatch(`codecommit::(?P<URL>[a-z0-9-]+)://(?P<PATH>[\\w\\.@\\:/\\-~]+)`, url)\n\tif len(match) != 0 {\n\t\treturn fmt.Sprintf(\"https://%s.console.aws.amazon.com/codesuite/codecommit/repositories/%s/browse?region=%s\", match[\"URL\"], match[\"PATH\"], match[\"URL\"])\n\t}\n\n\t// user@host.xz:/path/to/repo.git\n\tmatch = regex.FindNamedRegexMatch(`.*@(?P<URL>.*):(?P<PATH>.*)`, url)\n\tif len(match) == 0 {\n\t\treturn \"\"\n\t}\n\n\treturn fmt.Sprintf(\"https://%s/%s\", match[\"URL\"], strings.TrimSuffix(match[\"PATH\"], \".git\"))\n}\n\nfunc (g *Git) getUpstreamIcon() string {\n\tfallback := g.options.String(GitIcon, \"\\uE5FB \")\n\n\tg.RawUpstreamURL = g.getRemoteURL()\n\tif g.RawUpstreamURL == \"\" {\n\t\treturn fallback\n\t}\n\n\tg.UpstreamURL = g.cleanUpstreamURL(g.RawUpstreamURL)\n\n\t// allow overrides first\n\tcustom := g.options.KeyValueMap(UpstreamIcons, map[string]string{})\n\tfor key, value := range custom {\n\t\tif strings.Contains(g.UpstreamURL, key) {\n\t\t\treturn value\n\t\t}\n\t}\n\n\tdefaults := map[string]struct {\n\t\tIcon    options.Option\n\t\tDefault string\n\t}{\n\t\t\"github\":           {GithubIcon, \"\\uF408\"},\n\t\t\"gitlab\":           {GitlabIcon, \"\\uF296\"},\n\t\t\"bitbucket\":        {BitbucketIcon, \"\\uF171\"},\n\t\t\"dev.azure.com\":    {AzureDevOpsIcon, \"\\uEBE8\"},\n\t\t\"visualstudio.com\": {AzureDevOpsIcon, \"\\uEBE8\"},\n\t\t\"codecommit\":       {CodeCommit, \"\\uF270\"},\n\t\t\"codeberg\":         {CodebergIcon, \"\\uF330\"},\n\t}\n\n\tfor key, value := range defaults {\n\t\tif strings.Contains(g.UpstreamURL, key) {\n\t\t\treturn g.options.String(value.Icon, value.Default)\n\t\t}\n\t}\n\n\treturn fallback\n}\n\nfunc (g *Git) setStatus() {\n\taddToStatus := func(status string) {\n\t\tconst UNTRACKED = \"?\"\n\t\tif strings.HasPrefix(status, UNTRACKED) {\n\t\t\tg.Working.add(UNTRACKED)\n\t\t\treturn\n\t\t}\n\t\tif len(status) <= 4 {\n\t\t\treturn\n\t\t}\n\n\t\t// map conflicts separately when in a merge or rebase\n\t\tif g.Rebase != nil || g.Merge {\n\t\t\tconflict := \"AA\"\n\t\t\tfull := status[2:4]\n\t\t\tif full == conflict {\n\t\t\t\tg.Staging.add(conflict)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tworkingCode := status[3:4]\n\t\tstagingCode := status[2:3]\n\t\tg.Working.add(workingCode)\n\t\tg.Staging.add(stagingCode)\n\t\t// A newly staged file (A.) exists in the working directory but hasn't been committed yet.\n\t\t// Reflect it in Working so that templates tracking only Working can see the new file.\n\t\tif stagingCode == \"A\" && workingCode == \".\" {\n\t\t\tg.Working.add(\"A\")\n\t\t}\n\t}\n\n\tconst (\n\t\tHASH         = \"# branch.oid \"\n\t\tREF          = \"# branch.head \"\n\t\tUPSTREAM     = \"# branch.upstream \"\n\t\tBRANCHSTATUS = \"# branch.ab \"\n\t)\n\n\t// firstly assume that upstream is gone\n\tg.UpstreamGone = true\n\tstatusFormats := g.options.KeyValueMap(StatusFormats, map[string]string{})\n\n\tg.Working = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\tg.Staging = &GitStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\tuntrackedMode := g.getUntrackedFilesMode()\n\targs := []string{\"status\", untrackedMode, \"--branch\", \"--porcelain=2\"}\n\tignoreSubmodulesMode := g.getIgnoreSubmodulesMode()\n\tif len(ignoreSubmodulesMode) > 0 {\n\t\targs = append(args, ignoreSubmodulesMode)\n\t}\n\n\toutput := g.getGitCommandOutput(args...)\n\tfor line := range strings.SplitSeq(output, \"\\n\") {\n\t\tif strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 {\n\t\t\tg.ShortHash = line[len(HASH) : len(HASH)+7]\n\t\t\tg.Hash = line[len(HASH):]\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(line, REF) && len(line) > len(REF) {\n\t\t\tg.Ref = line[len(REF):]\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(line, UPSTREAM) && len(line) > len(UPSTREAM) {\n\t\t\t// status reports upstream, but upstream may be gone (must check BRANCHSTATUS)\n\t\t\tg.Upstream = line[len(UPSTREAM):]\n\t\t\tg.UpstreamGone = true\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.HasPrefix(line, BRANCHSTATUS) && len(line) > len(BRANCHSTATUS) {\n\t\t\tstatus := line[len(BRANCHSTATUS):]\n\t\t\tsplitted := strings.SplitN(status, \" \", 3)\n\t\t\tif len(splitted) >= 2 {\n\t\t\t\tg.Ahead, _ = strconv.Atoi(splitted[0])\n\t\t\t\tbehind, _ := strconv.Atoi(splitted[1])\n\t\t\t\tg.Behind = -behind\n\t\t\t}\n\t\t\t// confirmed: upstream exists\n\t\t\tg.UpstreamGone = false\n\t\t\tcontinue\n\t\t}\n\n\t\taddToStatus(line)\n\t}\n}\n\nfunc (g *Git) getGitCommandOutput(args ...string) string {\n\tif g.command == \"\" {\n\t\treturn \"\"\n\t}\n\n\targs = append([]string{\"-C\", g.repoRootDir, \"--no-optional-locks\", \"-c\", \"core.quotepath=false\", \"-c\", \"color.status=false\"}, args...)\n\tval, err := g.env.RunCommand(g.command, args...)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn val\n}\n\nfunc (g *Git) setHEADStatus() {\n\tbranchIcon := g.options.String(BranchIcon, \"\\uE0A0\")\n\tif g.Ref == DETACHED {\n\t\tg.Detached = true\n\t\tg.resolveDetachedHEAD()\n\t} else {\n\t\thead := g.formatBranch(g.Ref)\n\t\tg.HEAD = fmt.Sprintf(\"%s%s\", branchIcon, head)\n\t}\n\n\tformatDetached := func() string {\n\t\tif g.Detached {\n\t\t\treturn fmt.Sprintf(\"%sdetached at %s\", branchIcon, g.HEAD)\n\t\t}\n\t\treturn g.HEAD\n\t}\n\n\tgetPrettyNameOrigin := func(file string) string {\n\t\tvar origin string\n\t\thead := g.fileContent(g.mainSCMDir, file)\n\t\tif head == \"detached HEAD\" {\n\t\t\torigin = formatDetached()\n\t\t} else {\n\t\t\thead = strings.Replace(head, \"refs/heads/\", \"\", 1)\n\t\t\torigin = branchIcon + g.formatBranch(head)\n\t\t}\n\t\treturn origin\n\t}\n\n\tparseInt := func(file string) int {\n\t\tval, _ := strconv.Atoi(g.fileContent(g.mainSCMDir, file))\n\t\treturn val\n\t}\n\n\tif g.env.HasFolder(g.mainSCMDir + \"/rebase-merge\") {\n\t\thead := getPrettyNameOrigin(\"rebase-merge/head-name\")\n\t\tonto := g.getGitRefFileSymbolicName(\"rebase-merge/onto\")\n\t\tonto = g.formatBranch(onto)\n\t\tcurrent := parseInt(\"rebase-merge/msgnum\")\n\t\ttotal := parseInt(\"rebase-merge/end\")\n\t\ticon := g.options.String(RebaseIcon, \"\\uE728 \")\n\n\t\tg.Rebase = &Rebase{\n\t\t\tHEAD:    head,\n\t\t\tOnto:    onto,\n\t\t\tCurrent: current,\n\t\t\tTotal:   total,\n\t\t}\n\n\t\tg.HEAD = fmt.Sprintf(\"%s%s onto %s%s (%d/%d) at %s\", icon, head, branchIcon, onto, current, total, g.HEAD)\n\t\treturn\n\t}\n\n\tif g.env.HasFolder(g.mainSCMDir + \"/rebase-apply\") {\n\t\thead := getPrettyNameOrigin(\"rebase-apply/head-name\")\n\t\tcurrent := parseInt(\"rebase-apply/next\")\n\t\ttotal := parseInt(\"rebase-apply/last\")\n\t\ticon := g.options.String(RebaseIcon, \"\\uE728 \")\n\n\t\tg.Rebase = &Rebase{\n\t\t\tHEAD:    head,\n\t\t\tCurrent: current,\n\t\t\tTotal:   total,\n\t\t}\n\n\t\tg.HEAD = fmt.Sprintf(\"%s%s (%d/%d) at %s\", icon, head, current, total, g.HEAD)\n\t\treturn\n\t}\n\n\t// merge\n\tcommitIcon := g.options.String(CommitIcon, \"\\uF417\")\n\n\tif g.hasGitFile(\"MERGE_MSG\") {\n\t\tg.Merge = true\n\t\ticon := g.options.String(MergeIcon, \"\\uE727 \")\n\t\tmergeContext := g.fileContent(g.mainSCMDir, \"MERGE_MSG\")\n\t\tmatches := regex.FindNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext)\n\t\t// head := g.getGitRefFileSymbolicName(\"ORIG_HEAD\")\n\t\tif matches != nil && matches[\"theirs\"] != \"\" {\n\t\t\tvar headIcon, theirs string\n\t\t\tswitch matches[\"type\"] {\n\t\t\tcase \"tag\":\n\t\t\t\theadIcon = g.options.String(TagIcon, \"\\uF412\")\n\t\t\t\ttheirs = matches[\"theirs\"]\n\t\t\tcase \"commit\":\n\t\t\t\theadIcon = commitIcon\n\t\t\t\ttheirs = g.formatSHA(matches[\"theirs\"])\n\t\t\tdefault:\n\t\t\t\theadIcon = branchIcon\n\t\t\t\ttheirs = g.formatBranch(matches[\"theirs\"])\n\t\t\t}\n\t\t\tg.HEAD = fmt.Sprintf(\"%s%s%s into %s\", icon, headIcon, theirs, formatDetached())\n\t\t\treturn\n\t\t}\n\t}\n\n\t// sequencer status\n\t// see if a cherry-pick or revert is in progress, if the user has committed a\n\t// conflict resolution with 'git commit' in the middle of a sequence of picks or\n\t// reverts then CHERRY_PICK_HEAD/REVERT_HEAD will not exist so we have to read\n\t// the todo file.\n\tif g.hasGitFile(\"CHERRY_PICK_HEAD\") {\n\t\tg.CherryPick = true\n\t\tsha := g.fileContent(g.mainSCMDir, \"CHERRY_PICK_HEAD\")\n\t\tcherry := g.options.String(CherryPickIcon, \"\\uE29B \")\n\t\tg.HEAD = fmt.Sprintf(\"%s%s%s onto %s\", cherry, commitIcon, g.formatSHA(sha), formatDetached())\n\t\treturn\n\t}\n\n\tif g.hasGitFile(\"REVERT_HEAD\") {\n\t\tg.Revert = true\n\t\tsha := g.fileContent(g.mainSCMDir, \"REVERT_HEAD\")\n\t\trevert := g.options.String(RevertIcon, \"\\uF0E2 \")\n\t\tg.HEAD = fmt.Sprintf(\"%s%s%s onto %s\", revert, commitIcon, g.formatSHA(sha), formatDetached())\n\t\treturn\n\t}\n\n\tif g.hasGitFile(\"sequencer/todo\") {\n\t\ttodo := g.fileContent(g.mainSCMDir, \"sequencer/todo\")\n\t\tmatches := regex.FindNamedRegexMatch(`^(?P<action>p|pick|revert)\\s+(?P<sha>\\S+)`, todo)\n\t\tif matches != nil && matches[\"sha\"] != \"\" {\n\t\t\taction := matches[\"action\"]\n\t\t\tsha := matches[\"sha\"]\n\t\t\tswitch action {\n\t\t\tcase \"p\", \"pick\":\n\t\t\t\tg.CherryPick = true\n\t\t\t\tcherry := g.options.String(CherryPickIcon, \"\\uE29B \")\n\t\t\t\tg.HEAD = fmt.Sprintf(\"%s%s%s onto %s\", cherry, commitIcon, g.formatSHA(sha), formatDetached())\n\t\t\t\treturn\n\t\t\tcase \"revert\":\n\t\t\t\tg.Revert = true\n\t\t\t\trevert := g.options.String(RevertIcon, \"\\uF0E2 \")\n\t\t\t\tg.HEAD = fmt.Sprintf(\"%s%s%s onto %s\", revert, commitIcon, g.formatSHA(sha), formatDetached())\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\tg.HEAD = formatDetached()\n}\n\nfunc (g *Git) formatSHA(sha string) string {\n\tif len(sha) <= 7 {\n\t\treturn sha\n\t}\n\treturn sha[0:7]\n}\n\nfunc (g *Git) hasGitFile(file string) bool {\n\treturn g.env.HasFilesInDir(g.mainSCMDir, file)\n}\n\nfunc (g *Git) getGitRefFileSymbolicName(refFile string) string {\n\tref := g.fileContent(g.mainSCMDir, refFile)\n\treturn g.getGitCommandOutput(\"name-rev\", \"--name-only\", \"--exclude=tags/*\", ref)\n}\n\nfunc (g *Git) updateHEADReference() {\n\tHEADRef := g.fileContent(g.mainSCMDir, \"HEAD\")\n\tlog.Debug(\"HEADRef:\", HEADRef)\n\n\t// check if we are in a repo using reftables\n\tif HEADRef == \"ref: refs/heads/.invalid\" {\n\t\tlog.Debug(\"repo is using reftables\")\n\n\t\tHEADRef = g.getGitCommandOutput(\"rev-parse\", \"--symbolic-full-name\", \"HEAD\")\n\n\t\t// this is a detached head\n\t\tif strings.HasPrefix(HEADRef, \"fatal:\") {\n\t\t\tlog.Debug(\"detached HEAD detected\")\n\t\t\tg.Detached = true\n\t\t\tg.resolveDetachedHEAD()\n\t\t\treturn\n\t\t}\n\n\t\tif strings.HasPrefix(HEADRef, \"refs/heads/\") {\n\t\t\tHEADRef = \"ref: \" + HEADRef\n\t\t}\n\n\t\tlog.Debug(\"resolved HEADRef:\", HEADRef)\n\t}\n\n\tg.Detached = !strings.HasPrefix(HEADRef, \"ref:\")\n\tif branchName, ok := strings.CutPrefix(HEADRef, BRANCHPREFIX); ok {\n\t\tlog.Debug(\"current HEAD is a branch:\", branchName)\n\n\t\tg.Ref = branchName\n\t\tg.HEAD = fmt.Sprintf(\"%s%s\", g.options.String(BranchIcon, \"\\uE0A0\"), g.formatBranch(branchName))\n\n\t\treturn\n\t}\n\n\tg.resolveDetachedHEAD()\n}\n\nfunc (g *Git) resolveDetachedHEAD() {\n\tHEADRef := g.getGitCommandOutput(\"rev-parse\", \"HEAD\")\n\n\tif len(HEADRef) >= 7 {\n\t\tg.ShortHash = HEADRef[0:7]\n\t\tg.Hash = HEADRef[0:]\n\t}\n\tg.Ref = g.ShortHash\n\n\t// check for tag\n\ttagName := g.getGitCommandOutput(\"describe\", \"--tags\", \"--exact-match\")\n\tif len(tagName) > 0 {\n\t\tg.Ref = tagName\n\t\tg.HEAD = fmt.Sprintf(\"%s%s\", g.options.String(TagIcon, \"\\uF412\"), tagName)\n\t\treturn\n\t}\n\n\t// fallback to no commits found\n\tif g.ShortHash == \"\" {\n\t\tg.HEAD = g.options.String(NoCommitsIcon, \"\\uF594 \")\n\t\treturn\n\t}\n\n\tg.HEAD = fmt.Sprintf(\"%s%s\", g.options.String(CommitIcon, \"\\uF417\"), g.ShortHash)\n}\n\nfunc (g *Git) WorktreeCount() int {\n\tif g.worktreeCount > 0 {\n\t\treturn g.worktreeCount\n\t}\n\n\tworktreesFolder := filepath.Join(g.mainSCMDir, \"worktrees\")\n\n\tif !g.env.HasFolder(worktreesFolder) {\n\t\treturn 0\n\t}\n\n\tworktreeFolders := g.env.LsDir(worktreesFolder)\n\tvar count int\n\tfor _, folder := range worktreeFolders {\n\t\tif folder.IsDir() {\n\t\t\tcount++\n\t\t}\n\t}\n\n\treturn count\n}\n\nfunc (g *Git) getRemoteURL() string {\n\tupstream := regex.ReplaceAllString(\"/.*\", g.Upstream, \"\")\n\tif upstream == \"\" {\n\t\tupstream = origin\n\t}\n\n\tcfg, err := g.getGitConfig()\n\tif err != nil {\n\t\treturn g.getGitCommandOutput(\"remote\", \"get-url\", upstream)\n\t}\n\n\turl := cfg.Section(\"remote \\\"\" + upstream + \"\\\"\").Key(\"url\").String()\n\tif len(url) != 0 {\n\t\tlog.Debug(\"remote url found in config:\", url)\n\t\treturn url\n\t}\n\n\treturn g.getGitCommandOutput(\"remote\", \"get-url\", upstream)\n}\n\nfunc (g *Git) Remotes() map[string]string {\n\tvar remotes = make(map[string]string)\n\n\tcfg, err := g.getGitConfig()\n\tif err != nil {\n\t\treturn remotes\n\t}\n\n\tfor _, section := range cfg.Sections() {\n\t\tif !strings.HasPrefix(section.Name(), \"remote \") {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := strings.TrimPrefix(section.Name(), \"remote \")\n\t\tname = strings.Trim(name, \"\\\"\")\n\t\turl := section.Key(\"url\").String()\n\t\turl = g.cleanUpstreamURL(url)\n\t\tremotes[name] = url\n\t}\n\treturn remotes\n}\n\nfunc (g *Git) getUntrackedFilesMode() string {\n\treturn g.getSwitchMode(UntrackedModes, \"-u\", \"normal\")\n}\n\nfunc (g *Git) getIgnoreSubmodulesMode() string {\n\treturn g.getSwitchMode(IgnoreSubmodules, \"--ignore-submodules=\", \"\")\n}\n\nfunc (g *Git) getSwitchMode(property options.Option, gitSwitch, mode string) string {\n\trepoModes := g.options.KeyValueMap(property, map[string]string{})\n\t// make use of a wildcard for all repo's\n\tif val := repoModes[\"*\"]; len(val) != 0 {\n\t\tmode = val\n\t}\n\t// get the specific repo mode\n\tif val := repoModes[g.repoRootDir]; len(val) != 0 {\n\t\tmode = val\n\t}\n\tif mode == \"\" {\n\t\treturn \"\"\n\t}\n\treturn fmt.Sprintf(\"%s%s\", gitSwitch, mode)\n}\n\nfunc (g *Git) repoName() string {\n\tif !g.IsWorkTree {\n\t\treturn path.Base(g.convertToLinuxPath(g.repoRootDir))\n\t}\n\n\tind := strings.LastIndex(g.mainSCMDir, \".git/worktrees\")\n\tif ind > -1 {\n\t\treturn path.Base(g.mainSCMDir[:ind])\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "src/segments/git_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"gopkg.in/ini.v1\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\nconst (\n\tbranchName      = \"main\"\n\tdotGit          = \"dev/.git\"\n\tdotGitSubmodule = \"dev/.git/modules/submodule\"\n)\n\nfunc TestEnabledGitNotFound(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasParentFilePath\", \".git\", true).Return((*runtime.FileInfo)(nil), errors.New(\"no .git found (mock)\"))\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\n\tg := &Git{}\n\tg.Init(options.Map{}, env)\n\n\tassert.False(t, g.Enabled())\n}\n\nfunc TestEnabledInWorkingDirectory(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/hello\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"git\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"FileContent\", \"/dir/hello/HEAD\").Return(\"\")\n\tenv.MockGitCommand(fileInfo.Path, \"1234567890abcdef1234567890abcdef12345678\", \"rev-parse\", \"HEAD\")\n\tenv.MockGitCommand(fileInfo.Path, \"\", \"describe\", \"--tags\", \"--exact-match\")\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"HasParentFilePath\", \".git\", true).Return(fileInfo, nil)\n\tenv.On(\"PathSeparator\").Return(\"/\")\n\tenv.On(\"Home\").Return(poshHome)\n\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\tenv.On(\"DirMatchesOneOf\", testify_.Anything, testify_.Anything).Return(false)\n\n\tg := &Git{}\n\tg.Init(options.Map{}, env)\n\n\tassert.True(t, g.Enabled())\n\tassert.Equal(t, fileInfo.Path, g.mainSCMDir)\n}\n\nfunc TestResolveEmptyGitPath(t *testing.T) {\n\tbase := \"base\"\n\tassert.Equal(t, base, resolveGitPath(base, \"\"))\n}\n\nfunc TestEnabledInWorktree(t *testing.T) {\n\tcases := []struct {\n\t\tCase                  string\n\t\tWorkingFolder         string\n\t\tWorkingFolderAddon    string\n\t\tWorkingFolderContent  string\n\t\tExpectedRealFolder    string\n\t\tExpectedWorkingFolder string\n\t\tExpectedRootFolder    string\n\t\tExpectedEnabled       bool\n\t}{\n\t\t{\n\t\t\tCase:                  \"worktree\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         TestRootPath + \"dev/.git/worktrees/folder_worktree\",\n\t\t\tWorkingFolderAddon:    \"gitdir\",\n\t\t\tWorkingFolderContent:  TestRootPath + \"dev/worktree.git\\n\",\n\t\t\tExpectedWorkingFolder: TestRootPath + \"dev/.git/worktrees/folder_worktree\",\n\t\t\tExpectedRealFolder:    TestRootPath + \"dev/worktree\",\n\t\t\tExpectedRootFolder:    TestRootPath + dotGit,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"submodule\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         \"./.git/modules/submodule\",\n\t\t\tExpectedWorkingFolder: TestRootPath + dotGitSubmodule,\n\t\t\tExpectedRealFolder:    TestRootPath + dotGitSubmodule,\n\t\t\tExpectedRootFolder:    TestRootPath + dotGitSubmodule,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"submodule with root working folder\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         TestRootPath + dotGitSubmodule,\n\t\t\tExpectedWorkingFolder: TestRootPath + dotGitSubmodule,\n\t\t\tExpectedRealFolder:    TestRootPath + dotGitSubmodule,\n\t\t\tExpectedRootFolder:    TestRootPath + dotGitSubmodule,\n\t\t},\n\t\t{\n\t\t\tCase:                  \"submodule with worktrees\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         TestRootPath + \"dev/.git/modules/module/path/worktrees/location\",\n\t\t\tWorkingFolderAddon:    \"gitdir\",\n\t\t\tWorkingFolderContent:  TestRootPath + \"dev/worktree.git\\n\",\n\t\t\tExpectedWorkingFolder: TestRootPath + \"dev/.git/modules/module/path\",\n\t\t\tExpectedRealFolder:    TestRootPath + \"dev/worktree\",\n\t\t\tExpectedRootFolder:    TestRootPath + \"dev/.git/modules/module/path\",\n\t\t},\n\t\t{\n\t\t\tCase:                  \"separate git dir\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         TestRootPath + \"dev/separate/.git/posh\",\n\t\t\tExpectedWorkingFolder: TestRootPath + \"dev/\",\n\t\t\tExpectedRealFolder:    TestRootPath + \"dev/\",\n\t\t\tExpectedRootFolder:    TestRootPath + \"dev/separate/.git/posh\",\n\t\t},\n\t\t{\n\t\t\tCase:                  \"worktree with relative gitdir path\",\n\t\t\tExpectedEnabled:       true,\n\t\t\tWorkingFolder:         TestRootPath + \"dev/.git/worktrees/folder_worktree\",\n\t\t\tWorkingFolderAddon:    \"gitdir\",\n\t\t\tWorkingFolderContent:  \"../../../worktree/.git\\n\",\n\t\t\tExpectedWorkingFolder: TestRootPath + \"dev/.git/worktrees/folder_worktree\",\n\t\t\tExpectedRealFolder:    TestRootPath + \"dev/worktree\",\n\t\t\tExpectedRootFolder:    TestRootPath + dotGit,\n\t\t},\n\t}\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         TestRootPath + dotGit,\n\t\tParentFolder: TestRootPath + \"dev\",\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"FileContent\", TestRootPath+dotGit).Return(fmt.Sprintf(\"gitdir: %s\", tc.WorkingFolder))\n\t\tenv.On(\"FileContent\", filepath.Join(tc.WorkingFolder, tc.WorkingFolderAddon)).Return(tc.WorkingFolderContent)\n\t\tenv.On(\"HasFilesInDir\", tc.WorkingFolder, tc.WorkingFolderAddon).Return(true)\n\t\tenv.On(\"HasFilesInDir\", tc.WorkingFolder, \"HEAD\").Return(true)\n\t\tenv.On(\"PathSeparator\").Return(string(os.PathSeparator))\n\n\t\tg := &Git{}\n\t\tg.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, g.hasWorktree(fileInfo), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedWorkingFolder, g.mainSCMDir, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedRealFolder, g.repoRootDir, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedRootFolder, g.scmDir, tc.Case)\n\t}\n}\n\nfunc TestEnabledInBareRepo(t *testing.T) {\n\tcases := []struct {\n\t\tCase   string\n\t\tHEAD   string\n\t\tIsBare bool\n\t}{\n\t\t{\n\t\t\tCase:   \"Bare repo on main\",\n\t\t\tIsBare: true,\n\t\t\tHEAD:   \"ref: refs/heads/main\",\n\t\t},\n\t\t{\n\t\t\tCase:   \"Not a bare repo\",\n\t\t\tHEAD:   \"ref: refs/heads/main\",\n\t\t\tIsBare: false,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tpath := \"git\"\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"HasCommand\", \"git\").Return(true)\n\n\t\tconfigData := fmt.Sprintf(`[core]\n\t\tbare = %s`, strconv.FormatBool(tc.IsBare))\n\n\t\tenv.On(\"HasParentFilePath\", \".git\", true).Return(&runtime.FileInfo{IsDir: true, Path: path}, nil)\n\t\tenv.On(\"FileContent\", \"git/HEAD\").Return(tc.HEAD)\n\n\t\tprops := options.Map{\n\t\t\tFetchBareInfo: true,\n\t\t}\n\n\t\tg := &Git{}\n\t\tg.Init(props, env)\n\n\t\tg.configOnce = sync.Once{}\n\t\tg.configOnce.Do(func() {\n\t\t\tg.config, g.configErr = ini.Load([]byte(configData))\n\t\t})\n\n\t\t_ = g.Enabled()\n\n\t\tassert.Equal(t, tc.IsBare, g.IsBare, tc.Case)\n\t}\n}\n\nfunc TestGetGitOutputForCommand(t *testing.T) {\n\targs := []string{\"-C\", \"\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\", \"-c\", \"color.status=false\"}\n\tcommandArgs := []string{\"symbolic-ref\", \"--short\", \"HEAD\"}\n\twant := \"je suis le output\"\n\tenv := new(mock.Environment)\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"RunCommand\", \"git\", append(args, commandArgs...)).Return(want, nil)\n\tenv.On(\"GOOS\").Return(\"unix\")\n\n\tg := &Git{\n\t\tScm: Scm{\n\t\t\tcommand: GITCOMMAND,\n\t\t},\n\t}\n\tg.Init(options.Map{}, env)\n\n\tgot := g.getGitCommandOutput(commandArgs...)\n\tassert.Equal(t, want, got)\n}\n\nfunc TestSetGitHEADContextClean(t *testing.T) {\n\tcases := []struct {\n\t\tOurs        string\n\t\tExpected    string\n\t\tRef         string\n\t\tCase        string\n\t\tTotal       string\n\t\tStep        string\n\t\tTheirs      string\n\t\tRebaseMerge bool\n\t\tSequencer   bool\n\t\tRevert      bool\n\t\tCherryPick  bool\n\t\tMerge       bool\n\t\tRebaseApply bool\n\t}{\n\t\t{Case: \"detached on commit\", Ref: DETACHED, Expected: \"branch detached at commit 1234567\"},\n\t\t{Case: \"not detached, clean\", Ref: \"main\", Expected: \"branch main\"},\n\t\t{\n\t\t\tCase:        \"rebase merge\",\n\t\t\tRef:         DETACHED,\n\t\t\tExpected:    \"rebase branch origin/main onto branch main (1/2) at commit 1234567\",\n\t\t\tRebaseMerge: true,\n\t\t\tOurs:        \"refs/heads/origin/main\",\n\t\t\tTheirs:      \"main\",\n\t\t\tStep:        \"1\",\n\t\t\tTotal:       \"2\",\n\t\t},\n\t\t{\n\t\t\tCase:        \"rebase apply\",\n\t\t\tRef:         DETACHED,\n\t\t\tExpected:    \"rebase branch origin/main (1/2) at commit 1234567\",\n\t\t\tRebaseApply: true,\n\t\t\tOurs:        \"refs/heads/origin/main\",\n\t\t\tStep:        \"1\",\n\t\t\tTotal:       \"2\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"merge branch\",\n\t\t\tRef:      \"main\",\n\t\t\tExpected: \"merge branch feat-1 into branch main\",\n\t\t\tMerge:    true,\n\t\t\tTheirs:   \"branch 'feat-1'\",\n\t\t\tOurs:     \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"merge commit\",\n\t\t\tRef:      \"main\",\n\t\t\tExpected: \"merge commit 1234567 into branch main\",\n\t\t\tMerge:    true,\n\t\t\tTheirs:   \"commit '123456789101112'\",\n\t\t\tOurs:     \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"merge tag\",\n\t\t\tRef:      \"main\",\n\t\t\tExpected: \"merge tag 1.2.4 into branch main\",\n\t\t\tMerge:    true,\n\t\t\tTheirs:   \"tag '1.2.4'\",\n\t\t\tOurs:     \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"cherry pick\",\n\t\t\tRef:        \"main\",\n\t\t\tExpected:   \"pick commit 1234567 onto branch main\",\n\t\t\tCherryPick: true,\n\t\t\tTheirs:     \"123456789101012\",\n\t\t\tOurs:       \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"revert\",\n\t\t\tRef:      \"main\",\n\t\t\tExpected: \"revert commit 1234567 onto branch main\",\n\t\t\tRevert:   true,\n\t\t\tTheirs:   \"123456789101012\",\n\t\t\tOurs:     \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:      \"sequencer cherry\",\n\t\t\tRef:       \"main\",\n\t\t\tExpected:  \"pick commit 1234567 onto branch main\",\n\t\t\tSequencer: true,\n\t\t\tTheirs:    \"pick 123456789101012\",\n\t\t\tOurs:      \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:      \"sequencer cherry p\",\n\t\t\tRef:       \"main\",\n\t\t\tExpected:  \"pick commit 1234567 onto branch main\",\n\t\t\tSequencer: true,\n\t\t\tTheirs:    \"p 123456789101012\",\n\t\t\tOurs:      \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:      \"sequencer revert\",\n\t\t\tRef:       \"main\",\n\t\t\tExpected:  \"revert commit 1234567 onto branch main\",\n\t\t\tSequencer: true,\n\t\t\tTheirs:    \"revert 123456789101012\",\n\t\t\tOurs:      \"main\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"GOOS\").Return(\"unix\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.MockGitCommand(\"\", \"1234567890abcdef1234567890abcdef12345678\", \"rev-parse\", \"HEAD\")\n\t\tenv.MockGitCommand(\"\", \"\", \"describe\", \"--tags\", \"--exact-match\")\n\t\tenv.MockGitCommand(\"\", tc.Theirs, \"name-rev\", \"--name-only\", \"--exclude=tags/*\", tc.Theirs)\n\t\tenv.MockGitCommand(\"\", tc.Ours, \"name-rev\", \"--name-only\", \"--exclude=tags/*\", tc.Ours)\n\t\t// rebase merge\n\t\tenv.On(\"HasFolder\", \"/rebase-merge\").Return(tc.RebaseMerge)\n\t\tenv.On(\"FileContent\", \"/rebase-merge/head-name\").Return(tc.Ours)\n\t\tenv.On(\"FileContent\", \"/rebase-merge/onto\").Return(tc.Theirs)\n\t\tenv.On(\"FileContent\", \"/rebase-merge/msgnum\").Return(tc.Step)\n\t\tenv.On(\"FileContent\", \"/rebase-merge/end\").Return(tc.Total)\n\t\t// rebase apply\n\t\tenv.On(\"HasFolder\", \"/rebase-apply\").Return(tc.RebaseApply)\n\t\tenv.On(\"FileContent\", \"/rebase-apply/head-name\").Return(tc.Ours)\n\t\tenv.On(\"FileContent\", \"/rebase-apply/next\").Return(tc.Step)\n\t\tenv.On(\"FileContent\", \"/rebase-apply/last\").Return(tc.Total)\n\t\t// merge\n\t\tenv.On(\"HasFilesInDir\", \"\", \"MERGE_MSG\").Return(tc.Merge)\n\t\tenv.On(\"FileContent\", \"/MERGE_MSG\").Return(fmt.Sprintf(\"Merge %s into %s\", tc.Theirs, tc.Ours))\n\t\t// cherry pick\n\t\tenv.On(\"HasFilesInDir\", \"\", \"CHERRY_PICK_HEAD\").Return(tc.CherryPick)\n\t\tenv.On(\"FileContent\", \"/CHERRY_PICK_HEAD\").Return(tc.Theirs)\n\t\t// revert\n\t\tenv.On(\"HasFilesInDir\", \"\", \"REVERT_HEAD\").Return(tc.Revert)\n\t\tenv.On(\"FileContent\", \"/REVERT_HEAD\").Return(tc.Theirs)\n\t\t// sequencer\n\t\tenv.On(\"HasFilesInDir\", \"\", \"sequencer/todo\").Return(tc.Sequencer)\n\t\tenv.On(\"FileContent\", \"/sequencer/todo\").Return(tc.Theirs)\n\n\t\tprops := options.Map{\n\t\t\tBranchIcon:     \"branch \",\n\t\t\tCommitIcon:     \"commit \",\n\t\t\tRebaseIcon:     \"rebase \",\n\t\t\tMergeIcon:      \"merge \",\n\t\t\tCherryPickIcon: \"pick \",\n\t\t\tTagIcon:        \"tag \",\n\t\t\tRevertIcon:     \"revert \",\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: GITCOMMAND,\n\t\t\t},\n\t\t\tShortHash: \"1234567\",\n\t\t\tRef:       tc.Ref,\n\t\t}\n\t\tg.Init(props, env)\n\t\tg.mainSCMDir = \"\"\n\n\t\tg.setHEADStatus()\n\t\tassert.Equal(t, tc.Expected, g.HEAD, tc.Case)\n\t}\n}\n\nfunc TestSetPrettyHEADName(t *testing.T) {\n\tcases := []struct {\n\t\tCase         string\n\t\tExpected     string\n\t\tShortHash    string\n\t\tTag          string\n\t\tHEAD         string\n\t\tSymbolicName string\n\t}{\n\t\t{Case: \"main\", Expected: \"branch main\", HEAD: BRANCHPREFIX + \"main\"},\n\t\t{Case: \"no hash\", Expected: \"commit 1234567\", HEAD: \"12345678910\"},\n\t\t{Case: \"hash on tag\", ShortHash: \"132312322321\", Expected: \"tag tag-1\", HEAD: \"12345678910\", Tag: \"tag-1\"},\n\t\t{Case: \"no hash on tag\", Expected: \"tag tag-1\", Tag: \"tag-1\"},\n\t\t{Case: \"hash on commit\", ShortHash: \"1234567\", Expected: \"commit 1234567\"},\n\t\t{Case: \"no hash on commit\", Expected: \"commit 1234567\", HEAD: \"12345678910\"},\n\t\t{Case: \"reftable main branch\", Expected: \"branch main\", HEAD: \"ref: refs/heads/.invalid\", SymbolicName: \"refs/heads/main\"},\n\t\t{Case: \"reftable detached head\", Expected: \"commit 1234567\", HEAD: \"ref: refs/heads/.invalid\", SymbolicName: \"fatal: ref HEAD is not a symbolic ref\"},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"FileContent\", \"/HEAD\").Return(tc.HEAD)\n\t\tenv.On(\"GOOS\").Return(\"unix\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\t// Mock rev-parse HEAD for detached HEAD cases\n\t\theadValue := tc.HEAD\n\t\tif headValue == \"\" || strings.HasSuffix(tc.HEAD, \".invalid\") {\n\t\t\theadValue = \"12345678910\"\n\t\t}\n\t\tenv.MockGitCommand(\"\", headValue, \"rev-parse\", \"HEAD\")\n\t\tenv.MockGitCommand(\"\", tc.Tag, \"describe\", \"--tags\", \"--exact-match\")\n\t\tenv.MockGitCommand(\"\", tc.SymbolicName, \"rev-parse\", \"--symbolic-full-name\", \"HEAD\")\n\n\t\tprops := options.Map{\n\t\t\tBranchIcon: \"branch \",\n\t\t\tCommitIcon: \"commit \",\n\t\t\tTagIcon:    \"tag \",\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: GITCOMMAND,\n\t\t\t},\n\t\t\tShortHash: tc.ShortHash,\n\t\t}\n\t\tg.Init(props, env)\n\t\tg.mainSCMDir = \"\"\n\n\t\tg.updateHEADReference()\n\t\tassert.Equal(t, tc.Expected, g.HEAD, tc.Case)\n\t}\n}\n\nfunc TestSetGitStatus(t *testing.T) {\n\tcases := []struct {\n\t\tExpectedWorking      *GitStatus\n\t\tExpectedStaging      *GitStatus\n\t\tCase                 string\n\t\tOutput               string\n\t\tExpectedHash         string\n\t\tExpectedRef          string\n\t\tExpectedUpstream     string\n\t\tExpectedAhead        int\n\t\tExpectedBehind       int\n\t\tExpectedUpstreamGone bool\n\t\tRebase               bool\n\t\tMerge                bool\n\t}{\n\t\t{\n\t\t\tCase: \"all different options on working and staging, no remote\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t1 .R N...\n\t\t\t1 .C N...\n\t\t\t1 .M N...\n\t\t\t1 .m N...\n\t\t\t1 .A N...\n\t\t\t1 .D N...\n\t\t\t1 .A N...\n\t\t\t1 .U N...\n\t\t\t1 A. N...\n\t\t\t`,\n\t\t\tExpectedWorking:      &GitStatus{ScmStatus: ScmStatus{Modified: 4, Added: 3, Deleted: 1, Unmerged: 1}},\n\t\t\tExpectedStaging:      &GitStatus{ScmStatus: ScmStatus{Added: 1}},\n\t\t\tExpectedHash:         \"1234567\",\n\t\t\tExpectedRef:          \"rework-git-status\",\n\t\t\tExpectedUpstreamGone: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"all different options on working and staging, with remote\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t# branch.upstream origin/rework-git-status\n\t\t\t# branch.ab +0 -0\n\t\t\t1 .R N...\n\t\t\t1 .C N...\n\t\t\t1 .M N...\n\t\t\t1 .m N...\n\t\t\t1 .A N...\n\t\t\t1 .D N...\n\t\t\t1 .A N...\n\t\t\t1 .U N...\n\t\t\t1 A. N...\n\t\t\t`,\n\t\t\tExpectedWorking:  &GitStatus{ScmStatus: ScmStatus{Modified: 4, Added: 3, Deleted: 1, Unmerged: 1}},\n\t\t\tExpectedStaging:  &GitStatus{ScmStatus: ScmStatus{Added: 1}},\n\t\t\tExpectedUpstream: \"origin/rework-git-status\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"rework-git-status\",\n\t\t},\n\t\t{\n\t\t\tCase: \"remote with equal branch\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t# branch.upstream origin/rework-git-status\n\t\t\t# branch.ab +0 -0\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/rework-git-status\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"rework-git-status\",\n\t\t},\n\t\t{\n\t\t\tCase: \"remote with branch status\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t# branch.upstream origin/rework-git-status\n\t\t\t# branch.ab +2 -1\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/rework-git-status\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"rework-git-status\",\n\t\t\tExpectedAhead:    2,\n\t\t\tExpectedBehind:   1,\n\t\t},\n\t\t{\n\t\t\tCase: \"untracked files\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head main\n\t\t\t# branch.upstream origin/main\n\t\t\t# branch.ab +0 -0\n\t\t\t? q\n\t\t\t? qq\n\t\t\t? qqq\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/main\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"main\",\n\t\t\tExpectedWorking:  &GitStatus{ScmStatus: ScmStatus{Untracked: 3}},\n\t\t},\n\t\t{\n\t\t\tCase: \"remote branch was deleted\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head branch-is-gone\n\t\t\t# branch.upstream origin/branch-is-gone\n\t\t\t`,\n\t\t\tExpectedUpstream:     \"origin/branch-is-gone\",\n\t\t\tExpectedHash:         \"1234567\",\n\t\t\tExpectedRef:          \"branch-is-gone\",\n\t\t\tExpectedUpstreamGone: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"rebase with 2 merge conflicts\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t# branch.upstream origin/rework-git-status\n\t\t\t# branch.ab +0 -0\n\t\t\t1 AA N...\n\t\t\t1 AA N...\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/rework-git-status\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"rework-git-status\",\n\t\t\tRebase:           true,\n\t\t\tExpectedStaging:  &GitStatus{ScmStatus: ScmStatus{Unmerged: 2}},\n\t\t},\n\t\t{\n\t\t\tCase: \"merge with 4 merge conflicts\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head rework-git-status\n\t\t\t# branch.upstream origin/rework-git-status\n\t\t\t# branch.ab +0 -0\n\t\t\t1 AA N...\n\t\t\t1 AA N...\n\t\t\t1 AA N...\n\t\t\t1 AA N...\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/rework-git-status\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"rework-git-status\",\n\t\t\tMerge:            true,\n\t\t\tExpectedStaging:  &GitStatus{ScmStatus: ScmStatus{Unmerged: 4}},\n\t\t},\n\t\t{\n\t\t\tCase: \"staged new file also appears in working\",\n\t\t\tOutput: `\n\t\t\t# branch.oid 1234567891011121314\n\t\t\t# branch.head main\n\t\t\t# branch.upstream origin/main\n\t\t\t# branch.ab +0 -0\n\t\t\t1 .M N...\n\t\t\t1 A. N...\n\t\t\t? untracked1\n\t\t\t? untracked2\n\t\t\t? untracked3\n\t\t\t? untracked4\n\t\t\t`,\n\t\t\tExpectedUpstream: \"origin/main\",\n\t\t\tExpectedHash:     \"1234567\",\n\t\t\tExpectedRef:      \"main\",\n\t\t\tExpectedWorking:  &GitStatus{ScmStatus: ScmStatus{Modified: 1, Added: 1, Untracked: 4}},\n\t\t\tExpectedStaging:  &GitStatus{ScmStatus: ScmStatus{Added: 1}},\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(\"unix\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.MockGitCommand(\"\", strings.ReplaceAll(tc.Output, \"\\t\", \"\"), \"status\", \"-unormal\", \"--branch\", \"--porcelain=2\")\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: GITCOMMAND,\n\t\t\t},\n\t\t}\n\t\tg.Init(options.Map{}, env)\n\n\t\tif tc.ExpectedWorking == nil {\n\t\t\ttc.ExpectedWorking = &GitStatus{}\n\t\t}\n\n\t\tif tc.ExpectedStaging == nil {\n\t\t\ttc.ExpectedStaging = &GitStatus{}\n\t\t}\n\n\t\tif tc.Rebase {\n\t\t\tg.Rebase = &Rebase{}\n\t\t}\n\n\t\tg.Merge = tc.Merge\n\t\ttc.ExpectedStaging.Formats = map[string]string{}\n\t\ttc.ExpectedWorking.Formats = map[string]string{}\n\t\tg.setStatus()\n\t\tassert.Equal(t, tc.ExpectedStaging, g.Staging, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedWorking, g.Working, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedHash, g.ShortHash, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedRef, g.Ref, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedUpstream, g.Upstream, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedUpstreamGone, g.UpstreamGone, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedAhead, g.Ahead, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBehind, g.Behind, tc.Case)\n\t}\n}\n\nfunc TestGetStashContextZeroEntries(t *testing.T) {\n\tcases := []struct {\n\t\tStashContent string\n\t\tExpected     int\n\t}{\n\t\t{Expected: 0, StashContent: \"\"},\n\t\t{Expected: 2, StashContent: \"1\\n2\\n\"},\n\t\t{Expected: 4, StashContent: \"1\\n2\\n3\\n4\\n\\n\"},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"FileContent\", \"/logs/refs/stash\").Return(tc.StashContent)\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tmainSCMDir: \"\",\n\t\t\t},\n\t\t}\n\t\tg.Init(options.Map{}, env)\n\n\t\tgot := g.StashCount()\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestGitCleanSSHURL(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tUpstream string\n\t}{\n\t\t{Case: \"regular URL\", Expected: \"https://src.example.com/user/repo\", Upstream: \"/src.example.com/user/repo.git\"},\n\t\t{Case: \"domain:path\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"host.xz:/path/to/repo.git/\"},\n\t\t{Case: \"ssh with port\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://user@host.xz:1234/path/to/repo.git\"},\n\t\t{Case: \"ssh with 3-digit port\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://user@host.xz:234/path/to/repo.git\"},\n\t\t{Case: \"ssh with port, trailing slash\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://user@host.xz:1234/path/to/repo.git/\"},\n\t\t{Case: \"ssh without port\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://user@host.xz/path/to/repo.git/\"},\n\t\t{Case: \"ssh port, no user\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://host.xz:1234/path/to/repo.git\"},\n\t\t{Case: \"ssh no port, no user\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"ssh://host.xz/path/to/repo.git\"},\n\t\t{Case: \"rsync no port, no user\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"rsync://host.xz/path/to/repo.git/\"},\n\t\t{Case: \"git no port, no user\", Expected: \"https://host.xz/path/to/repo\", Upstream: \"git://host.xz/path/to/repo.git\"},\n\t\t{Case: \"gitea no port, no user\", Expected: \"https://src.example.com/user/repo\", Upstream: \"_gitea@src.example.com:user/repo.git\"},\n\t\t{Case: \"git@ with user\", Expected: \"https://github.com/JanDeDobbeleer/oh-my-posh\", Upstream: \"git@github.com:JanDeDobbeleer/oh-my-posh\"},\n\t\t{Case: \"unsupported\", Upstream: \"\\\\test\\\\repo.git\"},\n\t\t{Case: \"Azure DevOps, https\", Expected: \"https://dev.azure.com/posh/oh-my-posh/_git/website\", Upstream: \"https://posh@dev.azure.com/posh/oh-my-posh/_git/website\"},\n\t\t{Case: \"Azure DevOps, ssh\", Expected: \"https://dev.azure.com/posh/oh-my-posh/_git/website\", Upstream: \"git@ssh.dev.azure.com:v3/posh/oh-my-posh/website\"},\n\t}\n\tfor _, tc := range cases {\n\t\tg := &Git{}\n\t\tupstreamURL := g.cleanUpstreamURL(tc.Upstream)\n\t\tassert.Equal(t, tc.Expected, upstreamURL, tc.Case)\n\t}\n}\n\nfunc TestGitUpstream(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tUpstream string\n\t}{\n\t\t{Case: \"No upstream\", Expected: \"G\", Upstream: \"\"},\n\t\t{Case: \"SSH url\", Expected: \"G\", Upstream: \"ssh://git@git.my.domain:3001/ADIX7/dotconfig.git\"},\n\t\t{Case: \"Gitea\", Expected: \"EX\", Upstream: \"_gitea@src.example.com:user/repo.git\"},\n\t\t{Case: \"GitHub\", Expected: \"GH\", Upstream: \"github.com/test\"},\n\t\t{Case: \"GitLab\", Expected: \"GL\", Upstream: \"gitlab.com/test\"},\n\t\t{Case: \"Bitbucket\", Expected: \"BB\", Upstream: \"bitbucket.org/test\"},\n\t\t{Case: \"Azure DevOps\", Expected: \"AD\", Upstream: \"dev.azure.com/test\"},\n\t\t{Case: \"Azure DevOps Dos\", Expected: \"AD\", Upstream: \"test.visualstudio.com\"},\n\t\t{Case: \"CodeCommit\", Expected: \"AC\", Upstream: \"codecommit::eu-west-1://test-repository\"},\n\t\t{Case: \"Codeberg\", Expected: \"CB\", Upstream: \"codeberg.org:user/repo.git\"},\n\t\t{Case: \"Gitstash\", Expected: \"G\", Upstream: \"gitstash.com/test\"},\n\t\t{Case: \"My custom server\", Expected: \"CU\", Upstream: \"mycustom.server/test\"},\n\t\t{Case: \"GitHub with dash\", Expected: \"GH\", Upstream: \"github.com:pixel48/custom-reg\"},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"RunCommand\", \"git\", []string{\"-C\", \"\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\",\n\t\t\t\"-c\", \"color.status=false\", \"remote\", \"get-url\", origin}).Return(tc.Upstream, nil)\n\t\tenv.On(\"GOOS\").Return(\"unix\")\n\t\tprops := options.Map{\n\t\t\tGithubIcon:      \"GH\",\n\t\t\tGitlabIcon:      \"GL\",\n\t\t\tBitbucketIcon:   \"BB\",\n\t\t\tAzureDevOpsIcon: \"AD\",\n\t\t\tCodeCommit:      \"AC\",\n\t\t\tCodebergIcon:    \"CB\",\n\t\t\tGitIcon:         \"G\",\n\t\t\tUpstreamIcons: map[string]string{\n\t\t\t\t\"mycustom.server\": \"CU\",\n\t\t\t\t\"src.example.com\": \"EX\",\n\t\t\t},\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand:  GITCOMMAND,\n\t\t\t\tUpstream: \"origin/main\",\n\t\t\t},\n\t\t}\n\t\tg.Init(props, env)\n\n\t\tg.configOnce = sync.Once{}\n\t\tg.configOnce.Do(func() {\n\t\t\tg.configErr = errors.New(\"no config\")\n\t\t})\n\n\t\tupstreamIcon := g.getUpstreamIcon()\n\t\tassert.Equal(t, tc.Expected, upstreamIcon, tc.Case)\n\t}\n}\n\nfunc TestGetBranchStatus(t *testing.T) {\n\tcases := []struct {\n\t\tCase         string\n\t\tExpected     string\n\t\tUpstream     string\n\t\tAhead        int\n\t\tBehind       int\n\t\tUpstreamGone bool\n\t}{\n\t\t{Case: \"Equal with remote\", Expected: \"equal\", Upstream: branchName},\n\t\t{Case: \"Ahead\", Expected: \"up2\", Ahead: 2},\n\t\t{Case: \"Behind\", Expected: \"down8\", Behind: 8},\n\t\t{Case: \"Behind and ahead\", Expected: \"up7 down8\", Behind: 8, Ahead: 7},\n\t\t{Case: \"Gone\", Expected: \"gone\", Upstream: branchName, UpstreamGone: true},\n\t\t{Case: \"No remote\", Expected: \"\", Upstream: \"\"},\n\t\t{Case: \"Default (bug)\", Expected: \"\", Behind: -8, Upstream: \"wonky\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tBranchAheadIcon:     \"up\",\n\t\t\tBranchBehindIcon:    \"down\",\n\t\t\tBranchIdenticalIcon: \"equal\",\n\t\t\tBranchGoneIcon:      \"gone\",\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tUpstream: tc.Upstream,\n\t\t\t},\n\t\t\tAhead:        tc.Ahead,\n\t\t\tBehind:       tc.Behind,\n\t\t\tUpstreamGone: tc.UpstreamGone,\n\t\t}\n\t\tg.Init(props, new(mock.Environment))\n\n\t\tg.setBranchStatus()\n\t\tassert.Equal(t, tc.Expected, g.BranchStatus, tc.Case)\n\t}\n}\n\nfunc TestGitTemplateString(t *testing.T) {\n\tcases := []struct {\n\t\tGit      *Git\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{\n\t\t\tCase:     \"Only HEAD name\",\n\t\t\tExpected: branchName,\n\t\t\tTemplate: \"{{ .HEAD }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD:   branchName,\n\t\t\t\tBehind: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working area changes\",\n\t\t\tExpected: \"main \\uF044 +2 ~3\",\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD: branchName,\n\t\t\t\tWorking: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No working area changes\",\n\t\t\tExpected: branchName,\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD:    branchName,\n\t\t\t\tWorking: &GitStatus{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working and staging area changes\",\n\t\t\tExpected: \"main \\uF046 +5 ~1 \\uF044 +2 ~3\",\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD: branchName,\n\t\t\t\tWorking: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tStaging: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    5,\n\t\t\t\t\t\tModified: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working and staging area changes with separator\",\n\t\t\tExpected: \"main \\uF046 +5 ~1 | \\uF044 +2 ~3\",\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\", //nolint:lll\n\t\t\tGit: &Git{\n\t\t\t\tHEAD: branchName,\n\t\t\t\tWorking: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tStaging: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    5,\n\t\t\t\t\t\tModified: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working and staging area changes with separator and stash count\",\n\t\t\tExpected: \"main \\uF046 +5 ~1 | \\uF044 +2 ~3 \\ueb4b 3\",\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}\", //nolint:lll\n\t\t\tGit: &Git{\n\t\t\t\tHEAD: branchName,\n\t\t\t\tWorking: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tStaging: &GitStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    5,\n\t\t\t\t\t\tModified: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tstashCount: 3,\n\t\t\t\tposhgit:    true,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No local changes\",\n\t\t\tExpected: branchName,\n\t\t\tTemplate: \"{{ .HEAD }}{{ if .Staging.Changed }} \\uF046{{ .Staging.String }}{{ end }}{{ if .Working.Changed }} \\uF044{{ .Working.String }}{{ end }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD:    branchName,\n\t\t\t\tStaging: &GitStatus{},\n\t\t\t\tWorking: &GitStatus{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Upstream Icon\",\n\t\t\tExpected: \"from GitHub on main\",\n\t\t\tTemplate: \"from {{ .UpstreamIcon }} on {{ .HEAD }}\",\n\t\t\tGit: &Git{\n\t\t\t\tHEAD:         branchName,\n\t\t\t\tStaging:      &GitStatus{},\n\t\t\t\tWorking:      &GitStatus{},\n\t\t\t\tUpstreamIcon: \"GitHub\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\t\tenv := new(mock.Environment)\n\t\ttc.Git.env = env\n\t\ttc.Git.options = props\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Git), tc.Case)\n\t}\n}\n\nfunc TestGitUntrackedMode(t *testing.T) {\n\tcases := []struct {\n\t\tUntrackedModes map[string]string\n\t\tCase           string\n\t\tExpected       string\n\t}{\n\t\t{\n\t\t\tCase:     \"Default mode - no map\",\n\t\t\tExpected: \"-unormal\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Default mode - no match\",\n\t\t\tExpected: \"-unormal\",\n\t\t\tUntrackedModes: map[string]string{\n\t\t\t\t\"bar\": \"no\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No mode - match\",\n\t\t\tExpected: \"-uno\",\n\t\t\tUntrackedModes: map[string]string{\n\t\t\t\t\"foo\": \"no\",\n\t\t\t\t\"bar\": \"normal\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Global mode\",\n\t\t\tExpected: \"-uno\",\n\t\t\tUntrackedModes: map[string]string{\n\t\t\t\t\"*\": \"no\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tUntrackedModes: tc.UntrackedModes,\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\trepoRootDir: \"foo\",\n\t\t\t},\n\t\t}\n\t\tg.Init(props, new(mock.Environment))\n\n\t\tgot := g.getUntrackedFilesMode()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGitIgnoreSubmodules(t *testing.T) {\n\tcases := []struct {\n\t\tIgnoreSubmodules map[string]string\n\t\tCase             string\n\t\tExpected         string\n\t}{\n\t\t{\n\t\t\tCase:     \"Override\",\n\t\t\tExpected: \"--ignore-submodules=all\",\n\t\t\tIgnoreSubmodules: map[string]string{\n\t\t\t\t\"foo\": \"all\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Default mode - empty\",\n\t\t\tIgnoreSubmodules: map[string]string{\n\t\t\t\t\"bar\": \"no\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Global mode\",\n\t\t\tExpected: \"--ignore-submodules=dirty\",\n\t\t\tIgnoreSubmodules: map[string]string{\n\t\t\t\t\"*\": \"dirty\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tIgnoreSubmodules: tc.IgnoreSubmodules,\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\trepoRootDir: \"foo\",\n\t\t\t},\n\t\t}\n\t\tg.Init(props, new(mock.Environment))\n\n\t\tgot := g.getIgnoreSubmodulesMode()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGitCommit(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected *Commit\n\t\tOutput   string\n\t}{\n\t\t{\n\t\t\tCase: \"Clean commit\",\n\t\t\tOutput: `\n\t\t\tan:Jan De Dobbeleer\n\t\t\tae:jan@ohmyposh.dev\n\t\t\tcn:Jan De Dobbeleer\n\t\t\tce:jan@ohmyposh.dev\n\t\t\tat:1673176335\n\t\t\tsu:docs(error): you can't use cross segment properties\n\t\t\tha:1234567891011121314\n\t\t\trf:HEAD -> refs/heads/main, tag: refs/tags/tag-1, tag: refs/tags/0.3.4, refs/remotes/origin/main, refs/remotes/origin/dev, refs/heads/dev, refs/remotes/origin/HEAD\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor: &User{\n\t\t\t\t\tName:  \"Jan De Dobbeleer\",\n\t\t\t\t\tEmail: \"jan@ohmyposh.dev\",\n\t\t\t\t},\n\t\t\t\tCommitter: &User{\n\t\t\t\t\tName:  \"Jan De Dobbeleer\",\n\t\t\t\t\tEmail: \"jan@ohmyposh.dev\",\n\t\t\t\t},\n\t\t\t\tSubject:   \"docs(error): you can't use cross segment properties\",\n\t\t\t\tTimestamp: time.Unix(1673176335, 0),\n\t\t\t\tRefs: &Refs{\n\t\t\t\t\tTags:    []string{\"tag-1\", \"0.3.4\"},\n\t\t\t\t\tHeads:   []string{\"main\", \"dev\"},\n\t\t\t\t\tRemotes: []string{\"origin/main\", \"origin/dev\"},\n\t\t\t\t},\n\t\t\t\tSha: \"1234567891011121314\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"No commit output\",\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor:    &User{},\n\t\t\t\tCommitter: &User{},\n\t\t\t\tRefs:      &Refs{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"No author\",\n\t\t\tOutput: `\n\t\t\tan:\n\t\t\tae:\n\t\t\tcn:Jan De Dobbeleer\n\t\t\tce:jan@ohmyposh.dev\n\t\t\tat:1673176335\n\t\t\tsu:docs(error): you can't use cross segment properties\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor: &User{},\n\t\t\t\tCommitter: &User{\n\t\t\t\t\tName:  \"Jan De Dobbeleer\",\n\t\t\t\t\tEmail: \"jan@ohmyposh.dev\",\n\t\t\t\t},\n\t\t\t\tSubject:   \"docs(error): you can't use cross segment properties\",\n\t\t\t\tTimestamp: time.Unix(1673176335, 0),\n\t\t\t\tRefs:      &Refs{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"No refs\",\n\t\t\tOutput: `\n\t\t\trf:HEAD\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor:    &User{},\n\t\t\t\tCommitter: &User{},\n\t\t\t\tRefs:      &Refs{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Just tag ref\",\n\t\t\tOutput: `\n\t\t\trf:HEAD, tag: refs/tags/tag-1\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor:    &User{},\n\t\t\t\tCommitter: &User{},\n\t\t\t\tRefs: &Refs{\n\t\t\t\t\tTags: []string{\"tag-1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Feature branch including slash\",\n\t\t\tOutput: `\n\t\t\trf:HEAD, tag: refs/tags/feat/feat-1\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor:    &User{},\n\t\t\t\tCommitter: &User{},\n\t\t\t\tRefs: &Refs{\n\t\t\t\t\tTags: []string{\"feat/feat-1\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Bad timestamp\",\n\t\t\tOutput: `\n\t\t\tat:err\n\t\t\t`,\n\t\t\tExpected: &Commit{\n\t\t\t\tAuthor:    &User{},\n\t\t\t\tCommitter: &User{},\n\t\t\t\tRefs:      &Refs{},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.MockGitCommand(\"\", tc.Output, \"log\", \"-1\", \"--pretty=format:an:%an%nae:%ae%ncn:%cn%nce:%ce%nat:%at%nsu:%s%nha:%H%nrf:%D\", \"--decorate=full\")\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: GITCOMMAND,\n\t\t\t},\n\t\t}\n\t\tg.Init(options.Map{}, env)\n\n\t\tgot := g.Commit()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGitRemotes(t *testing.T) {\n\tcases := []struct {\n\t\tExpectedRemotes map[string]string\n\t\tCase            string\n\t\tConfig          string\n\t\tExpected        int\n\t}{\n\t\t{\n\t\t\tCase:            \"Empty config file\",\n\t\t\tExpected:        0,\n\t\t\tExpectedRemotes: map[string]string{},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Two remotes\",\n\t\t\tExpected: 2,\n\t\t\tConfig: `\n[remote \"origin\"]\n\turl = git@github.com:JanDeDobbeleer/test.git\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n[remote \"upstream\"]\n\turl = git@github.com:microsoft/test.git\n\tfetch = +refs/heads/*:refs/remotes/upstream/*\n`,\n\t\t\tExpectedRemotes: map[string]string{\n\t\t\t\t\"origin\":   \"https://github.com/JanDeDobbeleer/test\",\n\t\t\t\t\"upstream\": \"https://github.com/microsoft/test\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"One remote\",\n\t\t\tExpected: 1,\n\t\t\tConfig: `\n[remote \"origin\"]\n\turl = git@github.com:JanDeDobbeleer/test.git\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n`,\n\t\t\tExpectedRemotes: map[string]string{\n\t\t\t\t\"origin\": \"https://github.com/JanDeDobbeleer/test\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:            \"Broken config\",\n\t\t\tExpected:        0,\n\t\t\tConfig:          \"{{}}\",\n\t\t\tExpectedRemotes: map[string]string{},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Three remotes with different URL formats\",\n\t\t\tExpected: 3,\n\t\t\tConfig: `\n[remote \"origin\"]\n\turl = git@github.com:JanDeDobbeleer/test.git\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n[remote \"upstream\"]\n\turl = https://github.com/microsoft/test.git\n\tfetch = +refs/heads/*:refs/remotes/upstream/*\n[remote \"fork\"]\n\turl = git@gitlab.com:user/test.git\n\tfetch = +refs/heads/*:refs/remotes/fork/*\n`,\n\t\t\tExpectedRemotes: map[string]string{\n\t\t\t\t\"origin\":   \"https://github.com/JanDeDobbeleer/test\",\n\t\t\t\t\"upstream\": \"https://github.com/microsoft/test.git\",\n\t\t\t\t\"fork\":     \"https://gitlab.com/user/test\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\trepoRootDir: \"foo\",\n\t\t\t},\n\t\t}\n\t\tg.Init(options.Map{}, env)\n\n\t\tg.configOnce = sync.Once{}\n\t\tg.configOnce.Do(func() {\n\t\t\tg.config, g.configErr = ini.Load([]byte(tc.Config))\n\t\t})\n\n\t\tgot := g.Remotes()\n\t\tassert.Equal(t, tc.Expected, len(got), tc.Case)\n\n\t\t// Verify the actual remote names and URLs\n\t\tfor name, expectedURL := range tc.ExpectedRemotes {\n\t\t\tactualURL, exists := got[name]\n\t\t\tassert.True(t, exists, \"%s: expected remote '%s' to exist\", tc.Case, name)\n\t\t\tassert.Equal(t, expectedURL, actualURL, \"%s: remote '%s' URL mismatch\", tc.Case, name)\n\t\t}\n\t}\n}\n\nfunc TestGitRepoName(t *testing.T) {\n\tcases := []struct {\n\t\tCase       string\n\t\tExpected   string\n\t\tWorkingDir string\n\t\tRealDir    string\n\t\tIsWorkTree bool\n\t}{\n\t\t{\n\t\t\tCase:       \"In worktree\",\n\t\t\tExpected:   \"oh-my-posh\",\n\t\t\tIsWorkTree: true,\n\t\t\tWorkingDir: \"/Users/jan/Code/oh-my-posh/.git/worktrees/oh-my-posh2\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"Not in worktree\",\n\t\t\tExpected:   \"oh-my-posh\",\n\t\t\tIsWorkTree: false,\n\t\t\tRealDir:    \"/Users/jan/Code/oh-my-posh\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"In worktree, unexpected dir\",\n\t\t\tExpected:   \"\",\n\t\t\tIsWorkTree: true,\n\t\t\tWorkingDir: \"/Users/jan/Code/oh-my-posh2\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\trepoRootDir: tc.RealDir,\n\t\t\t\tmainSCMDir:  tc.WorkingDir,\n\t\t\t},\n\t\t\tIsWorkTree: tc.IsWorkTree,\n\t\t}\n\t\tg.Init(options.Map{}, env)\n\n\t\tgot := g.repoName()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestDisableWithJJEnabled(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\t// Mock .jj directory exists\n\tenv.On(\"HasParentFilePath\", \".jj\", false).Return(&runtime.FileInfo{Path: \"/dir/.jj\", IsDir: true}, nil)\n\n\tg := &Git{}\n\tprops := options.Map{\n\t\tDisableWithJJ: true,\n\t}\n\tg.Init(props, env)\n\n\tassert.False(t, g.Enabled())\n}\n\nfunc TestDisableWithJJDisabled(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/.git\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"git\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"FileContent\", \"/dir/.git/HEAD\").Return(\"\")\n\tenv.MockGitCommand(\"/dir\", \"1234567890abcdef1234567890abcdef12345678\", \"rev-parse\", \"HEAD\")\n\tenv.MockGitCommand(\"/dir\", \"\", \"describe\", \"--tags\", \"--exact-match\") // Use repo root, not .git dir\n\tenv.On(\"IsWsl\").Return(false)\n\t// Mock .jj directory exists\n\tenv.On(\"HasParentFilePath\", \".jj\", false).Return(&runtime.FileInfo{Path: \"/dir/.jj\", IsDir: true}, nil)\n\tenv.On(\"HasParentFilePath\", \".git\", true).Return(fileInfo, nil)\n\tenv.On(\"PathSeparator\").Return(\"/\")\n\tenv.On(\"Home\").Return(poshHome)\n\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\tenv.On(\"DirMatchesOneOf\", testify_.Anything, testify_.Anything).Return(false)\n\n\tg := &Git{}\n\tprops := options.Map{\n\t\tDisableWithJJ: false, // Property is disabled\n\t}\n\tg.Init(props, env)\n\n\tassert.True(t, g.Enabled()) // Should still be enabled since disable_with_jj is false\n}\n\nfunc TestDisableWithJJNoJJDirectory(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/.git\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"git\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"FileContent\", \"/dir/.git/HEAD\").Return(\"\")\n\tenv.MockGitCommand(\"/dir\", \"1234567890abcdef1234567890abcdef12345678\", \"rev-parse\", \"HEAD\")\n\tenv.MockGitCommand(\"/dir\", \"\", \"describe\", \"--tags\", \"--exact-match\") // Use repo root, not .git dir\n\tenv.On(\"IsWsl\").Return(false)\n\t// Mock .jj directory does not exist\n\tenv.On(\"HasParentFilePath\", \".jj\", false).Return((*runtime.FileInfo)(nil), errors.New(\"no .jj found\"))\n\tenv.On(\"HasParentFilePath\", \".git\", true).Return(fileInfo, nil)\n\tenv.On(\"PathSeparator\").Return(\"/\")\n\tenv.On(\"Home\").Return(poshHome)\n\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\tenv.On(\"DirMatchesOneOf\", testify_.Anything, testify_.Anything).Return(false)\n\n\tg := &Git{}\n\tprops := options.Map{\n\t\tDisableWithJJ: true, // Property is enabled but no .jj directory\n\t}\n\tg.Init(props, env)\n\n\tassert.True(t, g.Enabled()) // Should be enabled since .jj directory doesn't exist\n}\n\nfunc TestPushStatusAheadAndBehind(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tPushAheadCount     string\n\t\tPushBehindCount    string\n\t\tConfig             string\n\t\tExpectedPushAhead  int\n\t\tExpectedPushBehind int\n\t}{\n\t\t{\n\t\t\tCase:               \"ahead and behind\",\n\t\t\tPushAheadCount:     \"3\",\n\t\t\tPushBehindCount:    \"5\",\n\t\t\tExpectedPushAhead:  3,\n\t\t\tExpectedPushBehind: 5,\n\t\t},\n\t\t{\n\t\t\tCase:               \"only ahead\",\n\t\t\tPushAheadCount:     \"2\",\n\t\t\tPushBehindCount:    \"0\",\n\t\t\tExpectedPushAhead:  2,\n\t\t\tExpectedPushBehind: 0,\n\t\t},\n\t\t{\n\t\t\tCase:               \"only behind\",\n\t\t\tPushAheadCount:     \"0\",\n\t\t\tPushBehindCount:    \"7\",\n\t\t\tExpectedPushAhead:  0,\n\t\t\tExpectedPushBehind: 7,\n\t\t},\n\t\t{\n\t\t\tCase:               \"up to date\",\n\t\t\tPushAheadCount:     \"0\",\n\t\t\tPushBehindCount:    \"0\",\n\t\t\tExpectedPushAhead:  0,\n\t\t\tExpectedPushBehind: 0,\n\t\t},\n\t\t{\n\t\t\tCase:               \"remote from config\",\n\t\t\tPushAheadCount:     \"2\",\n\t\t\tPushBehindCount:    \"0\",\n\t\t\tExpectedPushAhead:  2,\n\t\t\tExpectedPushBehind: 0,\n\t\t\tConfig: `\n\t\t\t[branch \"main\"]\n\t\t\t\tremote = origin\n\t\t\t\tmerge = refs/heads/main\n\t\t\t`,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"RunCommand\", \"git\", []string{\"-C\", \"/dir\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\",\n\t\t\t\"-c\", \"color.status=false\", \"config\", \"--get\", \"remote.pushDefault\"}).Return(\"\", nil)\n\t\tenv.On(\"RunCommand\", \"git\", []string{\"-C\", \"/dir\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\",\n\t\t\t\"-c\", \"color.status=false\", \"rev-list\", \"--count\", \"origin/main..HEAD\"}).Return(tc.PushAheadCount, nil)\n\t\tenv.On(\"RunCommand\", \"git\", []string{\"-C\", \"/dir\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\",\n\t\t\t\"-c\", \"color.status=false\", \"rev-list\", \"--count\", \"HEAD..origin/main\"}).Return(tc.PushBehindCount, nil)\n\t\tenv.On(\"FileContent\", \"/dir/.git/config\").Return(\"\")\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand:     \"git\",\n\t\t\t\trepoRootDir: \"/dir\",\n\t\t\t\tscmDir:      \"/dir/.git\",\n\t\t\t\tUpstream:    \"origin/main\",\n\t\t\t},\n\t\t\tRef: \"main\",\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\tFetchPushStatus: true,\n\t\t}\n\n\t\tg.Init(props, env)\n\n\t\tg.configOnce = sync.Once{}\n\t\tg.configOnce.Do(func() {\n\t\t\tif len(tc.Config) > 0 {\n\t\t\t\tg.config, g.configErr = ini.Load([]byte(tc.Config))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tg.configErr = errors.New(\"no config\")\n\t\t})\n\n\t\tg.setPushStatus()\n\n\t\tassert.Equal(t, tc.ExpectedPushAhead, g.PushAhead, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedPushBehind, g.PushBehind, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/git_unix.go",
    "content": "//go:build !windows\n\npackage segments\n\nimport \"path/filepath\"\n\n// resolveGitPath resolves path relative to base.\nfunc resolveGitPath(base, path string) string {\n\tif filepath.IsAbs(path) {\n\t\treturn path\n\t}\n\n\treturn filepath.Join(base, path)\n}\n"
  },
  {
    "path": "src/segments/git_unix_test.go",
    "content": "//go:build !windows\n\npackage segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst TestRootPath = \"/\"\n\nfunc TestResolveGitPath(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tBase     string\n\t\tPath     string\n\t\tExpected string\n\t}{\n\t\t{\n\t\t\tCase:     \"relative path\",\n\t\t\tBase:     \"dir/\",\n\t\t\tPath:     \"sub\",\n\t\t\tExpected: \"dir/sub\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"absolute path\",\n\t\t\tBase:     \"/base\",\n\t\t\tPath:     \"/absolute/path\",\n\t\t\tExpected: \"/absolute/path\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, resolveGitPath(tc.Base, tc.Path), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/git_windows.go",
    "content": "package segments\n\nimport \"path/filepath\"\n\n// resolveGitPath resolves path relative to base.\nfunc resolveGitPath(base, path string) string {\n\tif path == \"\" {\n\t\treturn base\n\t}\n\n\tif filepath.IsAbs(path) {\n\t\treturn path\n\t}\n\n\t// Note that git on Windows uses slashes exclusively. And it's okay\n\t// because Windows actually accepts both directory separators. More\n\t// importantly, however, parts of the git segment depend on those\n\t// slashes.\n\tif path[0] == '/' {\n\t\t// path is a disk-relative path.\n\t\treturn filepath.VolumeName(base) + path\n\t}\n\n\treturn filepath.ToSlash(filepath.Join(base, path))\n}\n"
  },
  {
    "path": "src/segments/git_windows_test.go",
    "content": "//go:build windows\n\npackage segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst TestRootPath = \"C:/\"\n\nfunc TestResolveGitPath(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tBase     string\n\t\tPath     string\n\t\tExpected string\n\t}{\n\t\t{\n\t\t\tCase:     \"relative path\",\n\t\t\tBase:     \"dir\\\\\",\n\t\t\tPath:     \"sub\",\n\t\t\tExpected: \"dir/sub\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"absolute path\",\n\t\t\tBase:     \"C:\\\\base\",\n\t\t\tPath:     \"C:/absolute/path\",\n\t\t\tExpected: \"C:/absolute/path\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"disk-relative path\",\n\t\t\tBase:     \"C:\\\\base\",\n\t\t\tPath:     \"/absolute/path\",\n\t\t\tExpected: \"C:/absolute/path\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, resolveGitPath(tc.Base, tc.Path), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/gitversion.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n)\n\ntype GitVersionInfo struct {\n\tNuGetVersionV2                  string `json:\"NuGetVersionV2\"`\n\tFullSemVer                      string `json:\"FullSemVer\"`\n\tCommitDate                      string `json:\"CommitDate\"`\n\tAssemblySemVer                  string `json:\"AssemblySemVer\"`\n\tPreReleaseTagWithDash           string `json:\"PreReleaseTagWithDash\"`\n\tPreReleaseLabel                 string `json:\"PreReleaseLabel\"`\n\tPreReleaseLabelWithDash         string `json:\"PreReleaseLabelWithDash\"`\n\tAssemblySemFileVer              string `json:\"AssemblySemFileVer\"`\n\tCommitsSinceVersionSourcePadded string `json:\"CommitsSinceVersionSourcePadded\"`\n\tVersionSourceSha                string `json:\"VersionSourceSha\"`\n\tBuildMetaDataPadded             string `json:\"BuildMetaDataPadded\"`\n\tFullBuildMetaData               string `json:\"FullBuildMetaData\"`\n\tMajorMinorPatch                 string `json:\"MajorMinorPatch\"`\n\tNuGetVersion                    string `json:\"NuGetVersion\"`\n\tLegacySemVer                    string `json:\"LegacySemVer\"`\n\tLegacySemVerPadded              string `json:\"LegacySemVerPadded\"`\n\tPreReleaseTag                   string `json:\"PreReleaseTag\"`\n\tNuGetPreReleaseTag              string `json:\"NuGetPreReleaseTag\"`\n\tSemVer                          string `json:\"SemVer\"`\n\tInformationalVersion            string `json:\"InformationalVersion\"`\n\tBranchName                      string `json:\"BranchName\"`\n\tEscapedBranchName               string `json:\"EscapedBranchName\"`\n\tSha                             string `json:\"Sha\"`\n\tShortSha                        string `json:\"ShortSha\"`\n\tNuGetPreReleaseTagV2            string `json:\"NuGetPreReleaseTagV2\"`\n\tBuildMetaData                   int    `json:\"BuildMetaData\"`\n\tMajor                           int    `json:\"Major\"`\n\tPreReleaseNumber                int    `json:\"PreReleaseNumber\"`\n\tMinor                           int    `json:\"Minor\"`\n\tCommitsSinceVersionSource       int    `json:\"CommitsSinceVersionSource\"`\n\tWeightedPreReleaseNumber        int    `json:\"WeightedPreReleaseNumber\"`\n\tUncommittedChanges              int    `json:\"UncommittedChanges\"`\n\tPatch                           int    `json:\"Patch\"`\n}\n\ntype GitVersion struct {\n\tBase\n\n\tGitVersionInfo\n}\n\nfunc (n *GitVersion) Template() string {\n\treturn \" {{ .MajorMinorPatch }} \"\n}\n\nfunc (n *GitVersion) Enabled() bool {\n\tgitversion := \"gitversion\"\n\tif !n.env.HasCommand(gitversion) {\n\t\treturn false\n\t}\n\n\tresponse, err := n.env.RunCommand(gitversion, \"-output\", \"json\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tn.GitVersionInfo = GitVersionInfo{}\n\terr = json.Unmarshal([]byte(response), &n.GitVersionInfo)\n\n\treturn err == nil\n}\n"
  },
  {
    "path": "src/segments/gitversion_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestGitversion(t *testing.T) {\n\tcases := []struct {\n\t\tCacheError      error\n\t\tCommandError    error\n\t\tCase            string\n\t\tExpectedString  string\n\t\tResponse        string\n\t\tCacheResponse   string\n\t\tTemplate        string\n\t\tCacheTimeout    int\n\t\tExpectedEnabled bool\n\t\tHasGitversion   bool\n\t}{\n\t\t{Case: \"GitVersion not installed\"},\n\t\t{Case: \"GitVersion installed, no GitVersion.yml file\", HasGitversion: true, Response: \"Cannot find the .git directory\"},\n\t\t{\n\t\t\tCase:            \"Version\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"number\",\n\t\t\tHasGitversion:   true,\n\t\t\tResponse:        \"{ \\\"FullSemVer\\\": \\\"0.1.0\\\", \\\"SemVer\\\": \\\"number\\\" }\",\n\t\t\tTemplate:        \"{{ .SemVer }}\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Command Error\",\n\t\t\tHasGitversion: true,\n\t\t\tCommandError:  errors.New(\"error\"),\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\tenv.On(\"HasCommand\", \"gitversion\").Return(tc.HasGitversion)\n\t\tenv.On(\"Pwd\").Return(\"test-dir\")\n\t\tenv.On(\"RunCommand\", \"gitversion\", []string{\"-output\", \"json\"}).Return(tc.Response, tc.CommandError)\n\n\t\tgitversion := &GitVersion{}\n\t\tgitversion.Init(options.Map{}, env)\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = gitversion.Template()\n\t\t}\n\n\t\tenabled := gitversion.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif enabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, gitversion), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/golang.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"golang.org/x/mod/modfile\"\n)\n\ntype Golang struct {\n\tLanguage\n}\n\nconst (\n\tParseModFile  options.Option = \"parse_mod_file\"\n\tParseWorkFile options.Option = \"parse_work_file\"\n)\n\nfunc (g *Golang) Template() string {\n\treturn languageTemplate\n}\n\nfunc (g *Golang) Enabled() bool {\n\tg.extensions = []string{\"*.go\", \"go.mod\", \"go.sum\", \"go.work\", \"go.work.sum\"}\n\tg.tooling = map[string]*cmd{\n\t\t\"mod\": {\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)(.(?P<patch>[0-9]+))?))`,\n\t\t\tgetVersion: g.getVersion,\n\t\t},\n\t\t\"go\": {\n\t\t\texecutable: \"go\",\n\t\t\targs:       []string{\"version\"},\n\t\t\tregex:      `(?:go(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)(.(?P<patch>[0-9]+))?)))`,\n\t\t},\n\t}\n\tg.defaultTooling = []string{\"mod\", \"go\"}\n\tg.versionURLTemplate = \"https://golang.org/doc/go{{ .Major }}.{{ .Minor }}\"\n\n\treturn g.Language.Enabled()\n}\n\n// getVersion returns the version of the Go language\n// It first checks if the go.mod file is present and if it is, it parses the file to get the version\n// If the go.mod file is not present, it checks if the go.work file is present and if it is, it parses the file to get the version\n// If neither file is present, it returns an empty string\nfunc (g *Golang) getVersion() (string, error) {\n\tif g.options.Bool(ParseModFile, false) {\n\t\treturn g.parseModFile()\n\t}\n\n\tif g.options.Bool(ParseWorkFile, false) {\n\t\treturn g.parseWorkFile()\n\t}\n\n\treturn \"\", nil\n}\n\nfunc (g *Golang) parseModFile() (string, error) {\n\tgomod, err := g.env.HasParentFilePath(\"go.mod\", false)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tcontents := g.env.FileContent(gomod.Path)\n\tfile, err := modfile.Parse(gomod.Path, []byte(contents), nil)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif file.Go.Version != \"\" {\n\t\treturn file.Go.Version, nil\n\t}\n\n\t// ignore when no version is found in go.mod file\n\treturn \"\", nil\n}\n\nfunc (g *Golang) parseWorkFile() (string, error) {\n\tgoWork, err := g.env.HasParentFilePath(\"go.work\", false)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tcontents := g.env.FileContent(goWork.Path)\n\tversion, _ := regex.FindStringMatch(`go (\\d(\\.\\d{1,2})?(\\.\\d{1,2})?)`, contents, 1)\n\tif len(version) > 0 {\n\t\treturn version, nil\n\t}\n\n\t// ignore when no version is found in go.work file\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "src/segments/golang_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGolang(t *testing.T) {\n\tcases := []struct {\n\t\tCase                     string\n\t\tExpectedString           string\n\t\tVersion                  string\n\t\tParseModFile             bool\n\t\tHasModFileInParentDir    bool\n\t\tInvalidModfile           bool\n\t\tParseGoWorkFile          bool\n\t\tHasGoWorkFileInParentDir bool\n\t\tInvalidGoWorkFile        bool\n\t}{\n\t\t{Case: \"Go 1.15\", ExpectedString: \"1.15.8\", Version: \"go version go1.15.8 darwin/amd64\"},\n\t\t{Case: \"Go 1.16\", ExpectedString: \"1.16\", Version: \"go version go1.16 darwin/amd64\"},\n\t\t{Case: \"go.mod 1.26.0\", ParseModFile: true, HasModFileInParentDir: true, ExpectedString: \"1.26.0\"},\n\t\t{Case: \"no go.mod file fallback\", ParseModFile: true, ExpectedString: \"1.16\", Version: \"go version go1.16 darwin/amd64\"},\n\t\t{\n\t\t\tCase:                  \"invalid go.mod file fallback\",\n\t\t\tParseModFile:          true,\n\t\t\tHasModFileInParentDir: true,\n\t\t\tInvalidModfile:        true,\n\t\t\tExpectedString:        \"1.16\",\n\t\t\tVersion:               \"go version go1.16 darwin/amd64\",\n\t\t},\n\t\t{Case: \"go.work file\", ParseGoWorkFile: true, HasGoWorkFileInParentDir: true, ExpectedString: \"1.21\"},\n\t\t{\n\t\t\tCase:                     \"invalid go.work file fallback\",\n\t\t\tParseGoWorkFile:          true,\n\t\t\tHasGoWorkFileInParentDir: true,\n\t\t\tInvalidGoWorkFile:        true,\n\t\t\tExpectedString:           \"1.16\",\n\t\t\tVersion:                  \"go version go1.16 darwin/amd64\",\n\t\t},\n\t\t{\n\t\t\tCase:                     \"go.work file with go.mod file uses go.mod's version\",\n\t\t\tParseModFile:             true,\n\t\t\tHasModFileInParentDir:    true,\n\t\t\tParseGoWorkFile:          true,\n\t\t\tHasGoWorkFileInParentDir: true,\n\t\t\tExpectedString:           \"1.26.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"missing both go.mod and go.work file fallback\",\n\t\t\tParseModFile:    true,\n\t\t\tParseGoWorkFile: true,\n\t\t\tExpectedString:  \"1.16\",\n\t\t\tVersion:         \"go version go1.16 darwin/amd64\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"go\",\n\t\t\tversionParam:  \"version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.go\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.ParseModFile {\n\t\t\tprops[ParseModFile] = tc.ParseModFile\n\t\t\tfileInfo := &runtime.FileInfo{\n\t\t\t\tPath:         \"../go.mod\",\n\t\t\t\tParentFolder: \"./\",\n\t\t\t\tIsDir:        false,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tif !tc.HasModFileInParentDir {\n\t\t\t\terr = errors.New(\"no match\")\n\t\t\t}\n\t\t\tenv.On(\"HasParentFilePath\", \"go.mod\", false).Return(fileInfo, err)\n\n\t\t\tvar content string\n\t\t\tif tc.InvalidModfile {\n\t\t\t\tcontent = \"invalid go.mod file\"\n\t\t\t} else {\n\t\t\t\ttmp, _ := os.ReadFile(fileInfo.Path)\n\t\t\t\tcontent = string(tmp)\n\t\t\t}\n\n\t\t\tenv.On(\"FileContent\", fileInfo.Path).Return(content)\n\t\t}\n\n\t\tif tc.ParseGoWorkFile {\n\t\t\tprops[ParseWorkFile] = tc.ParseGoWorkFile\n\t\t\tfileInfo := &runtime.FileInfo{\n\t\t\t\tPath:         \"../test/go.work\",\n\t\t\t\tParentFolder: \"./\",\n\t\t\t\tIsDir:        false,\n\t\t\t}\n\n\t\t\tvar err error\n\t\t\tif !tc.HasGoWorkFileInParentDir {\n\t\t\t\terr = errors.New(\"no match\")\n\t\t\t}\n\n\t\t\tenv.On(\"HasParentFilePath\", \"go.work\", false).Return(fileInfo, err)\n\t\t\tvar content string\n\t\t\tif tc.InvalidGoWorkFile {\n\t\t\t\tcontent = \"invalid go.work file\"\n\t\t\t} else {\n\t\t\t\ttmp, _ := os.ReadFile(fileInfo.Path)\n\t\t\t\tcontent = string(tmp)\n\t\t\t}\n\n\t\t\tenv.On(\"FileContent\", fileInfo.Path).Return(content)\n\t\t}\n\n\t\tg := &Golang{}\n\t\tg.Init(props, env)\n\n\t\tassert.True(t, g.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, g.Template(), g), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/haskell.go",
    "content": "package segments\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\ntype Haskell struct {\n\tLanguage\n\n\tStackGhc bool\n}\n\nconst (\n\tStackGhcMode options.Option = \"stack_ghc_mode\"\n)\n\nfunc (h *Haskell) Template() string {\n\treturn languageTemplate\n}\n\nfunc (h *Haskell) Enabled() bool {\n\tghcRegex := `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`\n\n\th.extensions = []string{\"*.hs\", \"*.lhs\", \"stack.yaml\", \"package.yaml\", \"*.cabal\", \"cabal.project\"}\n\th.tooling = map[string]*cmd{\n\t\t\"ghc\": {\n\t\t\texecutable: \"ghc\",\n\t\t\targs:       []string{\"--numeric-version\"},\n\t\t\tregex:      ghcRegex,\n\t\t},\n\t\t\"stack\": {\n\t\t\texecutable: \"stack\",\n\t\t\targs:       []string{\"ghc\", \"--\", \"--numeric-version\"},\n\t\t\tregex:      ghcRegex,\n\t\t},\n\t}\n\th.defaultTooling = []string{\"ghc\"}\n\th.versionURLTemplate = \"https://www.haskell.org/ghc/download_ghc_{{ .Major }}_{{ .Minor }}_{{ .Patch }}.html\"\n\n\tswitch h.options.String(StackGhcMode, \"never\") {\n\tcase \"always\":\n\t\th.defaultTooling = []string{\"stack\"}\n\t\th.StackGhc = true\n\tcase \"package\":\n\t\t_, err := h.env.HasParentFilePath(\"stack.yaml\", false)\n\t\tif err == nil {\n\t\t\th.defaultTooling = []string{\"stack\"}\n\t\t\th.StackGhc = true\n\t\t}\n\t}\n\n\treturn h.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/haskell_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestHaskell(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tGhcVersion      string\n\t\tStackGhcVersion string\n\t\tStackGhcMode    string\n\t\tInStackPackage  bool\n\t\tStackGhc        bool\n\t}{\n\t\t{\n\t\t\tCase:            \"GHC 8.10.7\",\n\t\t\tExpectedString:  \"8.10.7\",\n\t\t\tGhcVersion:      \"8.10.7\",\n\t\t\tStackGhcVersion: \"9.0.2\",\n\t\t\tStackGhcMode:    \"never\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Stack GHC Mode - Always\",\n\t\t\tExpectedString:  \"9.0.2\",\n\t\t\tGhcVersion:      \"8.10.7\",\n\t\t\tStackGhcVersion: \"9.0.2\",\n\t\t\tStackGhcMode:    \"always\",\n\t\t\tStackGhc:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Stack GHC Mode - Package\",\n\t\t\tExpectedString:  \"9.0.2\",\n\t\t\tGhcVersion:      \"8.10.7\",\n\t\t\tStackGhcVersion: \"9.0.2\",\n\t\t\tStackGhcMode:    \"package\",\n\t\t\tInStackPackage:  true,\n\t\t\tStackGhc:        true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Stack GHC Mode - Package no stack.yaml\",\n\t\t\tExpectedString:  \"8.10.7\",\n\t\t\tGhcVersion:      \"8.10.7\",\n\t\t\tStackGhcVersion: \"9.0.2\",\n\t\t\tStackGhcMode:    \"package\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"ghc\",\n\t\t\tversionParam:  \"--numeric-version\",\n\t\t\tversionOutput: tc.GhcVersion,\n\t\t\textension:     \"*.hs\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.StackGhcMode == \"always\" || (tc.StackGhcMode == \"package\" && tc.InStackPackage) {\n\t\t\tenv.On(\"HasCommand\", \"stack\").Return(true)\n\t\t\tenv.On(\"RunCommand\", \"stack\", []string{\"ghc\", \"--\", \"--numeric-version\"}).Return(tc.StackGhcVersion, nil)\n\t\t}\n\n\t\tfileInfo := &runtime.FileInfo{\n\t\t\tPath:         \"../stack.yaml\",\n\t\t\tParentFolder: \"./\",\n\t\t\tIsDir:        false,\n\t\t}\n\n\t\tif tc.InStackPackage {\n\t\t\tvar err error\n\t\t\tenv.On(\"HasParentFilePath\", \"stack.yaml\", false).Return(fileInfo, err)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \"stack.yaml\", false).Return(fileInfo, errors.New(\"no match\"))\n\t\t}\n\n\t\tprops[StackGhcMode] = tc.StackGhcMode\n\n\t\th := &Haskell{}\n\t\th.Init(props, env)\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, h.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, h.Template(), h), failMsg)\n\t\tassert.Equal(t, tc.StackGhc, h.StackGhc, failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/helm.go",
    "content": "package segments\n\ntype Helm struct {\n\tBase\n\n\tVersion string\n}\n\nfunc (h *Helm) Enabled() bool {\n\tdisplayMode := h.options.String(DisplayMode, DisplayModeAlways)\n\tif displayMode != DisplayModeFiles {\n\t\treturn h.getVersion()\n\t}\n\n\tinChart := false\n\tfiles := []string{\"Chart.yml\", \"Chart.yaml\", \"helmfile.yaml\", \"helmfile.yml\"}\n\tfor _, file := range files {\n\t\tif _, err := h.env.HasParentFilePath(file, false); err == nil {\n\t\t\tinChart = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn inChart && h.getVersion()\n}\n\nfunc (h *Helm) Template() string {\n\treturn \" Helm {{.Version}}\"\n}\n\nfunc (h *Helm) getVersion() bool {\n\tcmd := \"helm\"\n\tif !h.env.HasCommand(cmd) {\n\t\treturn false\n\t}\n\n\tresult, err := h.env.RunCommand(cmd, \"version\", \"--short\", \"--template={{.Version}}\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\th.Version = result[1:]\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/helm_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_mock \"github.com/stretchr/testify/mock\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nfunc TestHelmSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tDisplayMode     string\n\t\tChartFile       string\n\t\tHelmExists      bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Helm not installed\",\n\t\t\tHelmExists:      false,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always inside chart\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"always\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always outside chart\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"always\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode files inside chart. Chart file Chart.yml\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"files\",\n\t\t\tChartFile:       \"Chart.yml\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always inside chart. Chart file Chart.yaml\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"files\",\n\t\t\tChartFile:       \"Chart.yaml\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always inside chart. Chart file helmfile.yaml\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"files\",\n\t\t\tChartFile:       \"helmfile.yaml\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always inside chart. Chart file helmfile.yml\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Helm 3.12.3\",\n\t\t\tDisplayMode:     \"files\",\n\t\t\tChartFile:       \"helmfile.yml\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"DisplayMode always outside chart\",\n\t\t\tHelmExists:      true,\n\t\t\tExpectedEnabled: false,\n\t\t\tDisplayMode:     \"files\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasCommand\", \"helm\").Return(tc.HelmExists)\n\t\tenv.On(\"RunCommand\", \"helm\", []string{\"version\", \"--short\", \"--template={{.Version}}\"}).Return(\"v3.12.3\", nil)\n\n\t\tenv.On(\"HasParentFilePath\", tc.ChartFile, false).Return(&runtime.FileInfo{}, nil)\n\t\tenv.On(\"HasParentFilePath\", testify_mock.Anything, false).Return(&runtime.FileInfo{}, errors.New(\"no such file or directory\"))\n\n\t\tprops := options.Map{\n\t\t\tDisplayMode: tc.DisplayMode,\n\t\t}\n\n\t\th := &Helm{}\n\t\th.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, h.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, h.Template(), h), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/http.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\n\t\"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n)\n\ntype HTTP struct {\n\tBase\n\n\tBody map[string]any\n}\n\nconst (\n\tMETHOD options.Option = \"method\"\n)\n\nfunc (h *HTTP) Template() string {\n\treturn \" {{ .Body }} \"\n}\n\nfunc (h *HTTP) Enabled() bool {\n\turl := h.options.String(URL, \"\")\n\tif url == \"\" {\n\t\treturn false\n\t}\n\n\tmethod := h.options.String(METHOD, \"GET\")\n\n\tif resolved, err := template.Render(url, nil); err == nil {\n\t\turl = resolved\n\t}\n\n\tresult, err := h.getResult(url, method)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\th.Body = result\n\treturn true\n}\n\nfunc (h *HTTP) getResult(url, method string) (map[string]any, error) {\n\tsetMethod := func(request *http.Request) {\n\t\trequest.Method = method\n\t}\n\n\tresultBody, err := h.env.HTTPRequest(url, nil, 10000, setMethod)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result map[string]any\n\terr = json.Unmarshal(resultBody, &result)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn result, nil\n}\n"
  },
  {
    "path": "src/segments/http_test.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestHTTPSegmentEnabled(t *testing.T) {\n\tcases := []struct {\n\t\texpected    any\n\t\tname        string\n\t\turl         string\n\t\tmethod      string\n\t\tresponse    string\n\t\tshouldError bool\n\t}{\n\t\t{\n\t\t\tname:        \"Valid URL with GET response\",\n\t\t\turl:         \"https://jsonplaceholder.typicode.com/posts/1\",\n\t\t\tmethod:      \"GET\",\n\t\t\tresponse:    `{\"id\": \"1\"}`,\n\t\t\texpected:    \"1\",\n\t\t\tshouldError: false,\n\t\t},\n\t\t{\n\t\t\tname:        \"Valid URL with POST response\",\n\t\t\turl:         \"https://jsonplaceholder.typicode.com/posts\",\n\t\t\tmethod:      \"POST\",\n\t\t\tresponse:    `{\"id\": \"101\"}`,\n\t\t\texpected:    \"101\",\n\t\t\tshouldError: false,\n\t\t},\n\t\t{\n\t\t\tname:        \"Valid URL with error response\",\n\t\t\turl:         \"https://api.example.com/data\",\n\t\t\tmethod:      \"GET\",\n\t\t\tshouldError: true,\n\t\t},\n\t\t{\n\t\t\tname:        \"Empty URL\",\n\t\t\turl:         \"\",\n\t\t\tmethod:      \"GET\",\n\t\t\tshouldError: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tenv := new(mock.Environment)\n\t\t\tprops := options.Map{\n\t\t\t\tURL:    tc.url,\n\t\t\t\tMETHOD: tc.method,\n\t\t\t}\n\n\t\t\tenv.On(\"HTTPRequest\", tc.url).Return([]byte(tc.response), func() error {\n\t\t\t\tif tc.shouldError {\n\t\t\t\t\treturn errors.New(\"error\")\n\t\t\t\t}\n\t\t\t\treturn nil\n\t\t\t}())\n\n\t\t\tcs := &HTTP{\n\t\t\t\tBase: Base{\n\t\t\t\t\tenv:     env,\n\t\t\t\t\toptions: props,\n\t\t\t\t},\n\t\t\t}\n\n\t\t\t_ = cs.Enabled()\n\t\t\tassert.Equal(t, tc.expected, cs.Body[\"id\"], tc.name)\n\t\t})\n\t}\n}\n\nfunc TestHTTPSegmentCache(t *testing.T) {\n\t// Simulate what happens when caching\n\tresponse := `{\"version\": \"39.2.6\", \"count\": 42, \"enabled\": true}`\n\n\t// Create and populate HTTP segment\n\toriginal := &HTTP{\n\t\tBase: Base{\n\t\t\tSegment: &Segment{\n\t\t\t\tText:  \" Electron: v39.2.6 \",\n\t\t\t\tIndex: 1,\n\t\t\t},\n\t\t},\n\t}\n\n\tvar result map[string]any\n\terr := json.Unmarshal([]byte(response), &result)\n\tassert.NoError(t, err)\n\toriginal.Body = result\n\n\t// Marshal to JSON (like setCache does)\n\tdata, err := json.Marshal(original)\n\tassert.NoError(t, err)\n\n\t// Unmarshal back (like restoreCache does)\n\trestored := &HTTP{\n\t\tBase: Base{\n\t\t\tSegment: &Segment{},\n\t\t},\n\t}\n\n\terr = json.Unmarshal(data, restored)\n\tassert.NoError(t, err)\n\n\t// Verify Body is restored correctly\n\tassert.NotNil(t, restored.Body, \"Body should not be nil\")\n\tassert.Equal(t, \"39.2.6\", restored.Body[\"version\"], \"version should be restored\")\n\tassert.Equal(t, float64(42), restored.Body[\"count\"], \"count should be restored\")\n\tassert.Equal(t, true, restored.Body[\"enabled\"], \"enabled should be restored\")\n}\n"
  },
  {
    "path": "src/segments/ipify.go",
    "content": "package segments\n\nimport (\n\t\"net\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype ipData struct {\n\tIP string `json:\"ip\"`\n}\n\ntype IPAPI interface {\n\tGet() (*ipData, error)\n}\n\ntype ipAPI struct {\n\thttp.Request\n}\n\nfunc (i *ipAPI) Get() (*ipData, error) {\n\turl := \"https://api.ipify.org?format=json\"\n\treturn http.Do[*ipData](&i.Request, url, nil)\n}\n\ntype IPify struct {\n\tBase\n\n\tapi IPAPI\n\tIP  string\n}\n\nconst (\n\tOFFLINE = \"OFFLINE\"\n)\n\nfunc (i *IPify) Template() string {\n\treturn \" {{ .IP }} \"\n}\n\nfunc (i *IPify) Enabled() bool {\n\tconst key = \"IP\"\n\n\tif ip, ok := cache.Get[string](cache.Device, key); ok {\n\t\ti.IP = ip\n\t\treturn true\n\t}\n\n\ti.initAPI()\n\n\tip, err := i.getResult()\n\tif err != nil {\n\t\treturn false\n\t}\n\n\ti.IP = ip\n\n\tduration := i.options.String(options.CacheDuration, string(cache.ONEDAY))\n\tcache.Set(cache.Device, key, i.IP, cache.Duration(duration))\n\n\treturn true\n}\n\nfunc (i *IPify) getResult() (string, error) {\n\tdata, err := i.api.Get()\n\tif dnsErr, OK := err.(*net.DNSError); OK && dnsErr.IsNotFound {\n\t\treturn OFFLINE, nil\n\t}\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn data.IP, err\n}\n\nfunc (i *IPify) initAPI() {\n\tif i.api != nil {\n\t\treturn\n\t}\n\n\trequest := &http.Request{\n\t\tEnv:         i.env,\n\t\tHTTPTimeout: i.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout),\n\t}\n\n\ti.api = &ipAPI{\n\t\tRequest: *request,\n\t}\n}\n"
  },
  {
    "path": "src/segments/ipify_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\ntype mockedipAPI struct {\n\ttestify_.Mock\n}\n\nfunc (s *mockedipAPI) Get() (*ipData, error) {\n\targs := s.Called()\n\treturn args.Get(0).(*ipData), args.Error(1)\n}\n\nfunc TestIpifySegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tIPDate          *ipData\n\t\tError           error\n\t\tExpectedString  string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"IP data\",\n\t\t\tIPDate:          &ipData{IP: \"127.0.0.1\"},\n\t\t\tExpectedString:  \"127.0.0.1\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Error\",\n\t\t\tError:           errors.New(\"network is unreachable\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Offline\",\n\t\t\tExpectedString:  OFFLINE,\n\t\t\tError:           &net.DNSError{IsNotFound: true},\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tapi := &mockedipAPI{}\n\t\tapi.On(\"Get\").Return(tc.IPDate, tc.Error)\n\n\t\tipify := &IPify{\n\t\t\tapi: api,\n\t\t\tBase: Base{\n\t\t\t\tenv:     &mock.Environment{},\n\t\t\t\toptions: options.Map{},\n\t\t\t},\n\t\t}\n\n\t\tenabled := ipify.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\tcache.DeleteAll(cache.Device)\n\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(&mock.Environment{}, ipify.Template(), ipify), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/java.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n)\n\ntype Java struct {\n\tLanguage\n}\n\nfunc (j *Java) Template() string {\n\treturn languageTemplate\n}\n\nfunc (j *Java) Enabled() bool {\n\tj.init()\n\n\treturn j.Language.Enabled()\n}\n\nfunc (j *Java) init() {\n\tjavaRegex := `(?: JRE)(?: \\(.*\\))? \\((?P<version>(?P<major>[0-9]+)(?:\\.(?P<minor>[0-9]+))?(?:\\.(?P<patch>[0-9]+))?).*\\),`\n\n\tj.extensions = []string{\n\t\t\"pom.xml\",\n\t\t\"build.gradle.kts\",\n\t\t\"build.sbt\",\n\t\t\".java-version\",\n\t\t\".deps.edn\",\n\t\t\"project.clj\",\n\t\t\"build.boot\",\n\t\t\"*.java\",\n\t\t\"*.class\",\n\t\t\"*.gradle\",\n\t\t\"*.jar\",\n\t\t\"*.clj\",\n\t\t\"*.cljc\",\n\t}\n\n\tj.tooling = map[string]*cmd{\n\t\t\"java\": {\n\t\t\texecutable: \"java\",\n\t\t\targs:       []string{\"-Xinternalversion\"},\n\t\t\tregex:      javaRegex,\n\t\t},\n\t}\n\tj.defaultTooling = []string{\"java\"}\n\n\tjavaHome := j.env.Getenv(\"JAVA_HOME\")\n\tif len(javaHome) > 0 {\n\t\tjava := fmt.Sprintf(\"%s/bin/java\", javaHome)\n\t\tj.tooling[\"java_home\"] = &cmd{\n\t\t\texecutable: java,\n\t\t\targs:       []string{\"-Xinternalversion\"},\n\t\t\tregex:      javaRegex,\n\t\t}\n\t\tj.defaultTooling = []string{\"java_home\", \"java\"}\n\t}\n}\n"
  },
  {
    "path": "src/segments/java_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestJava(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tVersion         string\n\t\tJavaHomeVersion string\n\t\tJavaHomeEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:           \"Zulu LTS\",\n\t\t\tExpectedString: \"11.0.13\",\n\t\t\tVersion:        \"OpenJDK 64-Bit Server VM (11.0.13+8-LTS) for windows-amd64 JRE (Zulu11.52+13-CA) (11.0.13+8-LTS), built on Oct 7 2021 16:00:23 by \\\"zulu_re\\\" with MS VC++ 15.9 (VS2017)\", //nolint:lll\n\t\t},\n\t\t{\n\t\t\tCase:           \"OpenJDK macOS\",\n\t\t\tExpectedString: \"1.8.0\",\n\t\t\tVersion:        \"OpenJDK 64-Bit Server VM (25.275-b01) for bsd-amd64 JRE (1.8.0_275-b01), built on Nov  9 2020 12:07:35 by \\\"jenkins\\\" with gcc 4.2.1\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"OpenJDK macOS with JAVA_HOME, no executable\",\n\t\t\tExpectedString: \"1.8.0\",\n\t\t\tVersion:        \"OpenJDK 64-Bit Server VM (25.275-b01) for bsd-amd64 JRE (1.8.0_275-b01), built on Nov  9 2020 12:07:35 by \\\"jenkins\\\" with gcc 4.2.1\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"OpenJDK macOS with JAVA_HOME and executable\",\n\t\t\tExpectedString:  \"1.7.0\",\n\t\t\tJavaHomeEnabled: true,\n\t\t\tJavaHomeVersion: \"OpenJDK 64-Bit Server VM (25.275-b01) for bsd-amd64 JRE (1.7.0_275-b01), built on Nov  9 2020 12:07:35 by \\\"jenkins\\\" with gcc 4.2.1\",\n\t\t\tVersion:         \"OpenJDK 64-Bit Server VM (25.275-b01) for bsd-amd64 JRE (1.8.0_275-b01), built on Nov  9 2020 12:07:35 by \\\"jenkins\\\" with gcc 4.2.1\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"openjdk version \\\"15.0.2\\\" 2021-01-19\",\n\t\t\tExpectedString:  \"15.0.2\",\n\t\t\tJavaHomeEnabled: true,\n\t\t\tJavaHomeVersion: \"OpenJDK 64-Bit Server VM (15.0.2+7) for windows-amd64 JRE (15.0.2+7), built on Jan 21 2021 05:54:57 by \\\"\\\" with MS VC++ 15.9 (VS2017)\",\n\t\t\tVersion:         \"OpenJDK 64-Bit Server VM (15.0.2+7) for windows-amd64 JRE (15.0.2+7), built on Jan 21 2021 05:54:57 by \\\"\\\" with MS VC++ 15.9 (VS2017)\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"openjdk version \\\"16\\\" 2021-03-16\",\n\t\t\tExpectedString:  \"16\",\n\t\t\tJavaHomeEnabled: true,\n\t\t\tJavaHomeVersion: \"OpenJDK 64-Bit Server VM (16+36) for windows-amd64 JRE (16+36), built on Mar 11 2021 10:56:33 by \\\"\\\" with MS VC++ 16.7 (VS2019)\",\n\t\t\tVersion:         \"OpenJDK 64-Bit Server VM (16+36) for windows-amd64 JRE (16+36), built on Mar 11 2021 10:56:33 by \\\"\\\" with MS VC++ 16.7 (VS2019)\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"java\",\n\t\t\tversionParam:  \"-Xinternalversion\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"pom.xml\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.JavaHomeEnabled {\n\t\t\tenv.On(\"Getenv\", \"JAVA_HOME\").Return(\"/usr/java\")\n\t\t\tenv.On(\"HasCommand\", \"/usr/java/bin/java\").Return(true)\n\t\t\tenv.On(\"RunCommand\", \"/usr/java/bin/java\", []string{\"-Xinternalversion\"}).Return(tc.JavaHomeVersion, nil)\n\t\t} else {\n\t\t\tenv.On(\"Getenv\", \"JAVA_HOME\").Return(\"\")\n\t\t}\n\n\t\tj := &Java{}\n\t\tj.Init(props, env)\n\t\tassert.True(t, j.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, j.Template(), j), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/jujutsu.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tJUJUTSUCOMMAND = \"jj\"\n\n\tIgnoreWorkingCopy options.Option = \"ignore_working_copy\"\n\tChangeIDMinLen    options.Option = \"change_id_min_len\"\n\tFetchAhead        options.Option = \"fetch_ahead_counter\"\n\tAheadIcon         options.Option = \"ahead_icon\"\n)\n\ntype JujutsuStatus struct {\n\tScmStatus\n}\n\nfunc (s *JujutsuStatus) add(code byte) {\n\tswitch code {\n\tcase 'D':\n\t\ts.Deleted++\n\tcase 'A', 'C': // added, copied\n\t\ts.Added++\n\tcase 'M':\n\t\ts.Modified++\n\tcase 'R': // renamed\n\t\ts.Moved++\n\t}\n}\n\ntype Jujutsu struct {\n\tWorking  *JujutsuStatus\n\tChangeID string\n\tScm\n}\n\nfunc (jj *Jujutsu) Template() string {\n\treturn \" \\uf1fa{{.ChangeID}}{{if .Working.Changed}} \\uf044 {{ .Working.String }}{{ end }} \"\n}\n\nfunc (jj *Jujutsu) Enabled() bool {\n\tdisplayStatus := jj.options.Bool(FetchStatus, false)\n\n\tif !jj.shouldDisplay(displayStatus) {\n\t\treturn false\n\t}\n\n\tstatusFormats := jj.options.KeyValueMap(StatusFormats, map[string]string{})\n\tjj.Working = &JujutsuStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\tif displayStatus {\n\t\tjj.setJujutsuStatus()\n\t}\n\n\treturn true\n}\n\nfunc (jj *Jujutsu) CacheKey() (string, bool) {\n\tdir, err := jj.env.HasParentFilePath(\".jj\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn dir.Path, true\n}\n\nfunc (jj *Jujutsu) ClosestBookmarks() string {\n\tstatusString, err := jj.getJujutsuCommandOutput(\"log\", \"-r\", \"heads(::@ & bookmarks())\", \"--no-graph\", \"-T\", \"bookmarks\")\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\tline, _, _ := strings.Cut(statusString, \"\\n\")\n\n\tif !jj.options.Bool(FetchAhead, false) || len(line) == 0 {\n\t\treturn line\n\t}\n\n\taheadIcon := jj.options.String(AheadIcon, \"\\u21e1\")\n\tmarks := strings.Split(line, \" \")\n\t// String to return for status\n\tvar endString strings.Builder\n\n\t// Closest bookmarks are all the same distance away from the working copy\n\t// so retrieve the distance to the first one and use it for all of them\n\n\trangeString := strings.Trim(marks[0], \"*\") + \"..@\"\n\n\taheadString, err := jj.getJujutsuCommandOutput(\"log\", \"--no-graph\", \"-T\", \"'.'\", \"-r\", rangeString)\n\tif err != nil {\n\t\treturn line\n\t}\n\n\taheadCounter := len(aheadString)\n\taheadCounterString := \"\"\n\n\tif aheadCounter != 0 {\n\t\taheadCounterString = aheadIcon + strconv.Itoa(aheadCounter)\n\t}\n\n\tlog.Debug(\"distance to nearest jj bookmark:\" + aheadCounterString)\n\n\t// Loop through each bookmark\n\tfor index, mark := range marks {\n\t\tif index > 0 {\n\t\t\tendString.WriteString(\" \")\n\t\t}\n\n\t\tendString.WriteString(mark + aheadCounterString)\n\t}\n\n\treturn endString.String()\n}\n\nfunc (jj *Jujutsu) shouldDisplay(displayStatus bool) bool {\n\tjjdir, err := jj.env.HasParentFilePath(\".jj\", false)\n\tif err != nil {\n\t\tlog.Debug(\"Jujutsu directory not found\")\n\t\treturn false\n\t}\n\n\tif displayStatus && !jj.hasCommand(JUJUTSUCOMMAND) {\n\t\tlog.Debug(\"Jujutsu command not found, skipping segment\")\n\t\treturn false\n\t}\n\n\tjj.setDir(jjdir.ParentFolder)\n\n\tjj.mainSCMDir = jjdir.Path\n\tjj.scmDir = jjdir.Path\n\t// convert the worktree file path to a windows one when in a WSL shared folder\n\tjj.repoRootDir = strings.TrimSuffix(jj.convertToWindowsPath(jjdir.Path), \"/.jj\")\n\n\treturn true\n}\n\nfunc (jj *Jujutsu) setDir(dir string) {\n\tdir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD\n\tif jj.env.GOOS() == runtime.WINDOWS {\n\t\tjj.Dir = strings.TrimSuffix(dir, `\\.jj`)\n\t\treturn\n\t}\n\n\tjj.Dir = strings.TrimSuffix(dir, \"/.jj\")\n}\n\nfunc (jj *Jujutsu) setJujutsuStatus() {\n\tstatusString, err := jj.getJujutsuCommandOutput(\"log\", \"-r\", \"@\", \"--no-graph\", \"-T\", jj.logTemplate())\n\tif err != nil {\n\t\treturn\n\t}\n\n\tlines := strings.Split(statusString, \"\\n\")\n\tjj.ChangeID = lines[0]\n\n\tfor _, line := range lines[1:] {\n\t\tif len(line) > 0 {\n\t\t\tjj.Working.add(line[0])\n\t\t}\n\t}\n}\n\nfunc (jj *Jujutsu) logTemplate() string {\n\t// https://jj-vcs.github.io/jj/latest/templates/#commit-keywords\n\treturn fmt.Sprintf(`change_id.shortest(%d) ++ \"\\n\" ++ diff.summary()`, jj.options.Int(ChangeIDMinLen, 0))\n}\n\nfunc (jj *Jujutsu) getJujutsuCommandOutput(command string, args ...string) (string, error) {\n\tcli := []string{\"--repository\", jj.repoRootDir, \"--no-pager\", \"--color\", \"never\"}\n\n\tif jj.options.Bool(IgnoreWorkingCopy, true) {\n\t\tcli = append(cli, \"--ignore-working-copy\")\n\t}\n\n\tcli = append(cli, command)\n\tcli = append(cli, args...)\n\n\treturn jj.env.RunCommand(jj.command, cli...)\n}\n"
  },
  {
    "path": "src/segments/jujutsu_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestJujutsuEnabledToolNotFound(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasParentFilePath\", \".jj\", false).Return(&runtime.FileInfo{}, errors.New(\"not found\"))\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\n\tjj := &Jujutsu{}\n\tjj.Init(options.Map{}, env)\n\n\tassert.False(t, jj.Enabled())\n}\n\nfunc TestJujutsuEnabledInWorkingDirectory(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/hello\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"jj\").Return(true)\n\tenv.On(\"HasParentFilePath\", \".jj\", false).Return(fileInfo, nil)\n\tenv.On(\"GOOS\").Return(\"\")\n\n\tjj := &Jujutsu{}\n\tjj.Init(options.Map{}, env)\n\n\tassert.True(t, jj.Enabled())\n\tassert.Equal(t, fileInfo.Path, jj.mainSCMDir)\n\tassert.Equal(t, fileInfo.Path, jj.repoRootDir)\n}\n\nfunc TestJujutsuGetIdInfo(t *testing.T) {\n\tcases := []struct {\n\t\tExpectedWorking  *JujutsuStatus\n\t\tCase             string\n\t\tLogOutput        string\n\t\tExpectedChangeID string\n\t}{\n\t\t{\n\t\t\tCase:             \"nochanges\",\n\t\t\tLogOutput:        \"a\\n\\n\",\n\t\t\tExpectedChangeID: \"a\",\n\t\t\tExpectedWorking: &JujutsuStatus{ScmStatus{\n\t\t\t\tDeleted:  0,\n\t\t\t\tAdded:    0,\n\t\t\t\tModified: 0,\n\t\t\t\tMoved:    0,\n\t\t\t}},\n\t\t},\n\t\t{\n\t\t\tCase: \"changed\",\n\t\t\tLogOutput: `b\nD deleted_file\nA added_file\nC {copied_file => new_file}\nM modified_file\nR {renamed_file => new_file}\n`,\n\t\t\tExpectedChangeID: \"b\",\n\t\t\tExpectedWorking: &JujutsuStatus{ScmStatus{\n\t\t\t\tDeleted:  1,\n\t\t\t\tAdded:    2,\n\t\t\t\tModified: 1,\n\t\t\t\tMoved:    1,\n\t\t\t}},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tfileInfo := &runtime.FileInfo{\n\t\t\tPath:         \"/dir/hello\",\n\t\t\tParentFolder: \"/dir\",\n\t\t\tIsDir:        true,\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"HasCommand\", \"jj\").Return(true)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"HasParentFilePath\", \".jj\", false).Return(fileInfo, nil)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Home\").Return(poshHome)\n\t\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\n\t\tjj := &Jujutsu{}\n\t\tjj.Init(props, env)\n\t\tenv.MockJjCommand(fileInfo.Path, tc.LogOutput, \"log\", \"-r\", \"@\", \"--no-graph\", \"-T\", jj.logTemplate())\n\n\t\tif tc.ExpectedWorking != nil {\n\t\t\ttc.ExpectedWorking.Formats = map[string]string{}\n\t\t}\n\n\t\tassert.True(t, jj.Enabled())\n\t\tassert.Equal(t, fileInfo.Path, jj.mainSCMDir)\n\t\tassert.Equal(t, fileInfo.Path, jj.repoRootDir)\n\t\tassert.Equal(t, tc.ExpectedWorking, jj.Working, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedChangeID, jj.ChangeID, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/julia.go",
    "content": "package segments\n\ntype Julia struct {\n\tLanguage\n}\n\nfunc (j *Julia) Template() string {\n\treturn languageTemplate\n}\n\nfunc (j *Julia) Enabled() bool {\n\tj.extensions = []string{\"*.jl\"}\n\tj.tooling = map[string]*cmd{\n\t\t\"julia\": {\n\t\t\texecutable: \"julia\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `julia version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tj.defaultTooling = []string{\"julia\"}\n\tj.versionURLTemplate = \"https://github.com/JuliaLang/julia/releases/tag/v{{ .Full }}\"\n\n\treturn j.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/julia_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestJulia(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Julia 1.6.0\", ExpectedString: \"1.6.0\", Version: \"julia version 1.6.0\"},\n\t\t{Case: \"Julia 1.6.1\", ExpectedString: \"1.6.1\", Version: \"julia version 1.6.1\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"julia\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.jl\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tj := &Julia{}\n\t\tj.Init(props, env)\n\t\tassert.True(t, j.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, j.Template(), j), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/kotlin.go",
    "content": "package segments\n\ntype Kotlin struct {\n\tLanguage\n}\n\nfunc (k *Kotlin) Template() string {\n\treturn languageTemplate\n}\n\nfunc (k *Kotlin) Enabled() bool {\n\tk.extensions = []string{\"*.kt\", \"*.kts\", \"*.ktm\"}\n\tk.tooling = map[string]*cmd{\n\t\t\"kotlin\": {\n\t\t\texecutable: \"kotlin\",\n\t\t\targs:       []string{\"-version\"},\n\t\t\tregex:      `Kotlin version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tk.defaultTooling = []string{\"kotlin\"}\n\tk.versionURLTemplate = \"https://github.com/JetBrains/kotlin/releases/tag/v{{ .Full }}\"\n\n\treturn k.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/kotlin_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestKotlin(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Kotlin 1.6.10\", ExpectedString: \"1.6.10\", Version: \"Kotlin version 1.6.10-release-923 (JRE 17.0.2+0)\"},\n\t\t{Case: \"Kotlin 1.6.0\", ExpectedString: \"1.6.0\", Version: \"Kotlin version 1.6.0-release-915 (JRE 17.0.2+0)\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"kotlin\",\n\t\t\tversionParam:  \"-version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.kt\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tk := &Kotlin{}\n\t\tk.Init(props, env)\n\t\tassert.True(t, k.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, k.Template(), k), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/kubectl.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\n// Whether to use kubectl or read kubeconfig ourselves\nconst (\n\tParseKubeConfig options.Option = \"parse_kubeconfig\"\n\tContextAliases  options.Option = \"context_aliases\"\n\tClusterAliases  options.Option = \"cluster_aliases\"\n)\n\ntype Kubectl struct {\n\tBase\n\n\tKubeContext\n\tContext string\n\tdirty   bool\n}\n\ntype KubeConfig struct {\n\tCurrentContext string `yaml:\"current-context\"`\n\tContexts       []struct {\n\t\tContext *KubeContext `yaml:\"context\"`\n\t\tName    string       `yaml:\"name\"`\n\t} `yaml:\"contexts\"`\n}\n\ntype KubeContext struct {\n\tCluster   string `yaml:\"cluster\"`\n\tUser      string `yaml:\"user\"`\n\tNamespace string `yaml:\"namespace\"`\n}\n\nfunc (k *Kubectl) Template() string {\n\treturn \" {{ .Context }}{{ if .Namespace }} :: {{ .Namespace }}{{ end }} \"\n}\n\nfunc (k *Kubectl) Enabled() bool {\n\tparseKubeConfig := k.options.Bool(ParseKubeConfig, true)\n\n\tif parseKubeConfig {\n\t\treturn k.doParseKubeConfig()\n\t}\n\n\treturn k.doCallKubectl()\n}\n\nfunc (k *Kubectl) doParseKubeConfig() bool {\n\t// Follow kubectl search rules (see https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable)\n\t// TL;DR: KUBECONFIG can contain a list of files. If it's empty ~/.kube/config is used. First file in list wins when merging keys.\n\tkubeconfigs := filepath.SplitList(k.env.Getenv(\"KUBECONFIG\"))\n\tif len(kubeconfigs) == 0 {\n\t\tkubeconfigs = []string{filepath.Join(k.env.Home(), \".kube/config\")}\n\t}\n\n\tcontexts := make(map[string]*KubeContext)\n\tk.Context = \"\"\n\n\tfor _, kubeconfig := range kubeconfigs {\n\t\tif kubeconfig == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tcontent := k.env.FileContent(kubeconfig)\n\n\t\tvar config KubeConfig\n\t\terr := yaml.Unmarshal([]byte(content), &config)\n\t\tif err != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tfor _, context := range config.Contexts {\n\t\t\tif _, exists := contexts[context.Name]; !exists {\n\t\t\t\tcontexts[context.Name] = context.Context\n\t\t\t}\n\t\t}\n\n\t\tif k.Context == \"\" {\n\t\t\tk.Context = config.CurrentContext\n\t\t}\n\n\t\tcontext, exists := contexts[k.Context]\n\t\tif !exists {\n\t\t\tcontinue\n\t\t}\n\n\t\tif context != nil {\n\t\t\tk.KubeContext = *context\n\t\t}\n\n\t\tk.SetContextAlias()\n\t\tk.SetClusterAlias()\n\t\tk.dirty = true\n\n\t\treturn true\n\t}\n\n\tdisplayError := k.options.Bool(options.DisplayError, false)\n\tif !displayError {\n\t\treturn false\n\t}\n\tk.setError(\"KUBECONFIG ERR\")\n\treturn true\n}\n\nfunc (k *Kubectl) doCallKubectl() bool {\n\tcmd := \"kubectl\"\n\tif !k.env.HasCommand(cmd) {\n\t\treturn false\n\t}\n\n\tresult, err := k.env.RunCommand(cmd, \"config\", \"view\", \"--output\", \"yaml\", \"--minify\")\n\tdisplayError := k.options.Bool(options.DisplayError, false)\n\tif err != nil && displayError {\n\t\tk.setError(\"KUBECTL ERR\")\n\t\treturn true\n\t}\n\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tvar config KubeConfig\n\terr = yaml.Unmarshal([]byte(result), &config)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tk.Context = config.CurrentContext\n\tk.SetContextAlias()\n\tk.dirty = true\n\n\tif len(config.Contexts) > 0 {\n\t\tk.KubeContext = *config.Contexts[0].Context\n\t\tk.SetClusterAlias()\n\t}\n\n\treturn true\n}\n\nfunc (k *Kubectl) setError(message string) {\n\tif k.Context == \"\" {\n\t\tk.Context = message\n\t}\n\n\tk.Namespace = message\n\tk.User = message\n\tk.Cluster = message\n}\n\nfunc (k *Kubectl) SetContextAlias() {\n\taliases := k.options.KeyValueMap(ContextAliases, map[string]string{})\n\tif alias, exists := aliases[k.Context]; exists {\n\t\tk.Context = alias\n\t}\n}\n\nfunc (k *Kubectl) SetClusterAlias() {\n\taliases := k.options.KeyValueMap(ClusterAliases, map[string]string{})\n\tif alias, exists := aliases[k.Cluster]; exists {\n\t\tk.Cluster = alias\n\t}\n}\n"
  },
  {
    "path": "src/segments/kubectl_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\ttestKubectlAllInfoTemplate = \"{{.Context}} :: {{.Namespace}} :: {{.User}} :: {{.Cluster}}\"\n\tcontextMarker              = \"currentcontextmarker\"\n)\n\nfunc TestKubectlSegment(t *testing.T) {\n\tstandardTemplate := \"{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}\"\n\tlsep := string(filepath.ListSeparator)\n\n\tcases := []struct {\n\t\tFiles           map[string]string\n\t\tContextAliases  map[string]string\n\t\tClusterAliases  map[string]string\n\t\tCluster         string\n\t\tKubeconfig      string\n\t\tContext         string\n\t\tNamespace       string\n\t\tUserName        string\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tKubectlExists   bool\n\t\tParseKubeConfig bool\n\t\tKubectlErr      bool\n\t\tExpectedEnabled bool\n\t\tDisplayError    bool\n\t}{\n\t\t{\n\t\t\tCase:            \"kubeconfig incomplete\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tKubeconfig:      contextMarker + lsep + \"contextdefinitionincomplete\",\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tExpectedString:  \"ctx ::  ::  ::\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{Case: \"disabled\", Template: standardTemplate, KubectlExists: false, Context: \"aaa\", Namespace: \"bbb\", ExpectedEnabled: false},\n\t\t{\n\t\t\tCase:            \"all information\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tKubectlExists:   true,\n\t\t\tContext:         \"aaa\",\n\t\t\tNamespace:       \"bbb\",\n\t\t\tUserName:        \"ccc\",\n\t\t\tCluster:         \"ddd\",\n\t\t\tExpectedString:  \"aaa :: bbb :: ccc :: ddd\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{Case: \"no namespace\", Template: standardTemplate, KubectlExists: true, Context: \"aaa\", ExpectedString: \"aaa\", ExpectedEnabled: true},\n\t\t{\n\t\t\tCase:            \"kubectl context alias\",\n\t\t\tTemplate:        standardTemplate,\n\t\t\tKubectlExists:   true,\n\t\t\tContext:         \"aaa\",\n\t\t\tNamespace:       \"bbb\",\n\t\t\tContextAliases:  map[string]string{\"aaa\": \"ccc\"},\n\t\t\tExpectedString:  \"ccc :: bbb\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubectl error\",\n\t\t\tTemplate:        standardTemplate,\n\t\t\tDisplayError:    true,\n\t\t\tKubectlExists:   true,\n\t\t\tContext:         \"aaa\",\n\t\t\tNamespace:       \"bbb\",\n\t\t\tKubectlErr:      true,\n\t\t\tExpectedString:  \"KUBECTL ERR :: KUBECTL ERR\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{Case: \"kubectl error hidden\", Template: standardTemplate, DisplayError: false, KubectlExists: true, Context: \"aaa\", Namespace: \"bbb\", KubectlErr: true, ExpectedEnabled: false},\n\t\t{\n\t\t\tCase:            \"kubeconfig home\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tExpectedString:  \"aaa :: bbb :: ccc :: ddd\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubeconfig context alias\",\n\t\t\tTemplate:        standardTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tContextAliases:  map[string]string{\"aaa\": \"ccc\"},\n\t\t\tExpectedString:  \"ccc :: bbb\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubectl cluster alias\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tKubectlExists:   true,\n\t\t\tContext:         \"aaa\",\n\t\t\tNamespace:       \"bbb\",\n\t\t\tUserName:        \"ccc\",\n\t\t\tCluster:         \"ddd\",\n\t\t\tClusterAliases:  map[string]string{\"ddd\": \"production\"},\n\t\t\tExpectedString:  \"aaa :: bbb :: ccc :: production\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubeconfig cluster alias\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tClusterAliases:  map[string]string{\"ddd\": \"prod\"},\n\t\t\tExpectedString:  \"aaa :: bbb :: ccc :: prod\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubeconfig context and cluster alias\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tContextAliases:  map[string]string{\"aaa\": \"my-context\"},\n\t\t\tClusterAliases:  map[string]string{\"ddd\": \"my-cluster\"},\n\t\t\tExpectedString:  \"my-context :: bbb :: ccc :: my-cluster\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"kubeconfig multiple current marker first\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tKubeconfig:      \"\" + lsep + contextMarker + lsep + \"contextdefinition\" + lsep + \"contextredefinition\",\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tExpectedString:  \"ctx :: ns :: usr :: cl\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:     \"kubeconfig multiple context first\",\n\t\t\tTemplate: testKubectlAllInfoTemplate, ParseKubeConfig: true,\n\t\t\tKubeconfig:      \"contextdefinition\" + lsep + \"contextredefinition\" + lsep + contextMarker + lsep,\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tExpectedString:  \"ctx :: ns :: usr :: cl\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"kubeconfig error hidden\", Template: testKubectlAllInfoTemplate, ParseKubeConfig: true, Kubeconfig: \"invalid\", Files: testKubeConfigFiles, ExpectedEnabled: false},\n\t\t{\n\t\t\tCase:            \"kubeconfig error\",\n\t\t\tTemplate:        testKubectlAllInfoTemplate,\n\t\t\tParseKubeConfig: true,\n\t\t\tKubeconfig:      \"invalid\",\n\t\t\tFiles:           testKubeConfigFiles,\n\t\t\tDisplayError:    true,\n\t\t\tExpectedString:  \"KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR :: KUBECONFIG ERR\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasCommand\", \"kubectl\").Return(tc.KubectlExists)\n\n\t\tvar kubeconfig string\n\t\tcontent, err := os.ReadFile(\"../test/kubectl.yml\")\n\t\tif err == nil {\n\t\t\tkubeconfig = fmt.Sprintf(string(content), tc.Cluster, tc.UserName, tc.Namespace, tc.Context)\n\t\t}\n\n\t\tvar kubectlErr error\n\t\tif tc.KubectlErr {\n\t\t\tkubectlErr = &runtime.CommandError{\n\t\t\t\tErr:      \"oops\",\n\t\t\t\tExitCode: 1,\n\t\t\t}\n\t\t}\n\n\t\tenv.On(\"RunCommand\", \"kubectl\", []string{\"config\", \"view\", \"--output\", \"yaml\", \"--minify\"}).Return(kubeconfig, kubectlErr)\n\t\tenv.On(\"Getenv\", \"KUBECONFIG\").Return(tc.Kubeconfig)\n\n\t\tfor path, content := range tc.Files {\n\t\t\tenv.On(\"FileContent\", path).Return(content)\n\t\t}\n\n\t\tenv.On(\"Home\").Return(\"testhome\")\n\n\t\tprops := options.Map{\n\t\t\toptions.DisplayError: tc.DisplayError,\n\t\t\tParseKubeConfig:      tc.ParseKubeConfig,\n\t\t\tContextAliases:       tc.ContextAliases,\n\t\t\tClusterAliases:       tc.ClusterAliases,\n\t\t}\n\n\t\tk := &Kubectl{}\n\t\tk.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, k.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, k), tc.Case)\n\t\t}\n\t}\n}\n\nvar testKubeConfigFiles = map[string]string{\n\tfilepath.Join(\"testhome\", \".kube/config\"): `\napiVersion: v1\ncontexts:\n  - context:\n      cluster: ddd\n      user: ccc\n      namespace: bbb\n    name: aaa\ncurrent-context: aaa\n`,\n\t\"contextdefinition\": `\napiVersion: v1\ncontexts:\n  - context:\n      cluster: cl\n      user: usr\n      namespace: ns\n    name: ctx\n`,\n\tcontextMarker: `\napiVersion: v1\ncurrent-context: ctx\n`,\n\t\"invalid\": \"this is not yaml\",\n\t\"contextdefinitionincomplete\": `\napiVersion: v1\ncontexts:\n  - name: ctx\n`,\n\t\"contextredefinition\": `\napiVersion: v1\ncontexts:\n  - context:\n      cluster: wrongcl\n      user: wrongu\n      namespace: wrongns\n    name: ctx\n`,\n}\n"
  },
  {
    "path": "src/segments/language.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\truntime_ \"runtime\"\n\n\t\"slices\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n)\n\nconst (\n\tlanguageTemplate = \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n\tnoVersion        = \"NO VERSION\"\n)\n\ntype loadContext func()\n\ntype inContext func() bool\n\ntype getVersion func() (string, error)\ntype matchesVersionFile func() (string, bool)\n\ntype Version struct {\n\tFull          string\n\tMajor         string\n\tMinor         string\n\tPatch         string\n\tPrerelease    string\n\tBuildMetadata string\n\tURL           string\n\tExecutable    string\n\tExpected      string\n}\n\ntype cmd struct {\n\tgetVersion         getVersion\n\texecutable         string\n\tregex              string\n\tversionURLTemplate string\n\targs               []string\n}\n\nfunc (c *cmd) parse(versionInfo string) (*Version, error) {\n\tvalues := regex.FindNamedRegexMatch(c.regex, versionInfo)\n\tif len(values) == 0 {\n\t\treturn nil, errors.New(\"cannot parse version string\")\n\t}\n\n\tversion := &Version{\n\t\tFull:          values[\"version\"],\n\t\tMajor:         values[\"major\"],\n\t\tMinor:         values[\"minor\"],\n\t\tPatch:         values[\"patch\"],\n\t\tPrerelease:    values[\"prerelease\"],\n\t\tBuildMetadata: values[\"buildmetadata\"],\n\t}\n\treturn version, nil\n}\n\ntype Language struct {\n\tBase\n\n\tprojectRoot        *runtime.FileInfo\n\tloadContext        loadContext\n\tinContext          inContext\n\tmatchesVersionFile matchesVersionFile\n\tVersion\n\tdisplayMode        string\n\tError              string\n\tversionURLTemplate string\n\tname               string\n\tcommands           []*cmd\n\ttooling            map[string]*cmd\n\tdefaultTooling     []string\n\tprojectFiles       []string\n\tfolders            []string\n\textensions         []string\n\texitCode           int\n\thomeEnabled        bool\n\tMismatch           bool\n}\n\nconst (\n\t// DisplayMode sets the display mode (always, when_in_context, never)\n\tDisplayMode options.Option = \"display_mode\"\n\t// DisplayModeAlways displays the segment always\n\tDisplayModeAlways string = \"always\"\n\t// DisplayModeFiles displays the segment when the current folder contains certain extensions\n\tDisplayModeFiles string = \"files\"\n\t// DisplayModeEnvironment displays the segment when the environment has a language's context\n\tDisplayModeEnvironment string = \"environment\"\n\t// DisplayModeContext displays the segment when the environment or files is active\n\tDisplayModeContext string = \"context\"\n\t// MissingCommandText sets the text to display when the command is not present in the system\n\tMissingCommandText options.Option = \"missing_command_text\"\n\t// HomeEnabled displays the segment in the HOME folder or not\n\tHomeEnabled options.Option = \"home_enabled\"\n\t// LanguageExtensions the list of extensions to validate\n\tLanguageExtensions options.Option = \"extensions\"\n\t// LanguageFolders the list of folders to validate\n\tLanguageFolders options.Option = \"folders\"\n\t// Tooling allows enabling additional version fetching tools\n\tTooling options.Option = \"tooling\"\n)\n\nfunc (l *Language) getName() string {\n\t_, file, _, _ := runtime_.Caller(2)\n\tbase := filepath.Base(file)\n\treturn base[:len(base)-3]\n}\n\nfunc (l *Language) Enabled() bool {\n\tl.name = l.getName()\n\t// override default extensions if needed\n\tl.extensions = l.options.StringArray(LanguageExtensions, l.extensions)\n\tl.folders = l.options.StringArray(LanguageFolders, l.folders)\n\tinHomeDir := func() bool {\n\t\treturn l.env.Pwd() == l.env.Home()\n\t}\n\n\tvar enabled bool\n\n\thomeEnabled := l.options.Bool(HomeEnabled, l.homeEnabled)\n\tif inHomeDir() && !homeEnabled {\n\t\treturn false\n\t}\n\n\tif len(l.projectFiles) != 0 && l.hasProjectFiles() {\n\t\tenabled = true\n\t}\n\n\tif !enabled {\n\t\t// set default mode when not set\n\t\tif l.displayMode == \"\" {\n\t\t\tl.displayMode = l.options.String(DisplayMode, DisplayModeFiles)\n\t\t}\n\n\t\tl.loadLanguageContext()\n\n\t\tswitch l.displayMode {\n\t\tcase DisplayModeAlways:\n\t\t\tenabled = true\n\t\tcase DisplayModeEnvironment:\n\t\t\tenabled = l.inLanguageContext()\n\t\tcase DisplayModeFiles:\n\t\t\tenabled = l.hasLanguageFiles() || l.hasLanguageFolders()\n\t\tcase DisplayModeContext:\n\t\t\tfallthrough\n\t\tdefault:\n\t\t\tenabled = l.hasLanguageFiles() || l.hasLanguageFolders() || l.inLanguageContext() || l.hasProjectFiles()\n\t\t}\n\t}\n\n\tl.loadTooling()\n\n\tif !enabled || !l.options.Bool(options.FetchVersion, true) {\n\t\treturn enabled\n\t}\n\n\terr := l.setVersion()\n\tif err != nil {\n\t\tl.Error = err.Error()\n\t}\n\n\tif l.matchesVersionFile != nil {\n\t\texpected, match := l.matchesVersionFile()\n\t\tif !match {\n\t\t\tl.Mismatch = true\n\t\t\tl.Expected = expected\n\t\t}\n\t}\n\n\treturn enabled\n}\n\n// loadTooling builds the commands list from the tooling map based on the tooling configuration.\n// Users can override the default tooling via the Tooling option.\n// This allows specifying which tools should be used to fetch versions\n// (e.g., \"uv\" for Python to use UV package manager).\nfunc (l *Language) loadTooling() {\n\tenabledTools := l.options.StringArray(Tooling, l.defaultTooling)\n\tif len(enabledTools) == 0 {\n\t\treturn\n\t}\n\n\tvar commands []*cmd\n\tfor _, tool := range enabledTools {\n\t\tif command, exists := l.tooling[tool]; exists {\n\t\t\tcommands = append(commands, command)\n\t\t}\n\t}\n\n\tl.commands = commands\n}\n\nfunc (l *Language) hasLanguageFiles() bool {\n\treturn slices.ContainsFunc(l.extensions, l.env.HasFiles)\n}\n\nfunc (l *Language) hasProjectFiles() bool {\n\tfor _, extension := range l.projectFiles {\n\t\tif configPath, err := l.env.HasParentFilePath(extension, false); err == nil {\n\t\t\tl.projectRoot = configPath\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (l *Language) hasLanguageFolders() bool {\n\treturn slices.ContainsFunc(l.folders, l.env.HasFolder)\n}\n\n// setVersion parses the version string returned by the command\nfunc (l *Language) setVersion() error {\n\tvar lastError error\n\n\tcacheKey := fmt.Sprintf(\"version_%s\", l.name)\n\n\tif versionCache, OK := cache.Get[Version](cache.Device, cacheKey); OK {\n\t\tl.Version = versionCache\n\t\treturn nil\n\t}\n\n\tfor _, command := range l.commands {\n\t\tversionStr, err := l.runCommand(command)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tlastError = err\n\t\t\tcontinue\n\t\t}\n\n\t\tversion, err := command.parse(versionStr)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\tlastError = fmt.Errorf(\"err parsing info from %s with %s\", command.executable, versionStr)\n\t\t\tcontinue\n\t\t}\n\n\t\tl.Version = *version\n\t\tif command.versionURLTemplate != \"\" {\n\t\t\tl.versionURLTemplate = command.versionURLTemplate\n\t\t}\n\n\t\tl.buildVersionURL()\n\t\tl.Executable = command.executable\n\n\t\tduration := l.options.String(options.CacheDuration, string(cache.NONE))\n\t\tcache.Set(cache.Device, cacheKey, l.Version, cache.Duration(duration))\n\n\t\treturn nil\n\t}\n\n\tif lastError != nil {\n\t\treturn lastError\n\t}\n\n\treturn errors.New(l.options.String(MissingCommandText, \"\"))\n}\n\nfunc (l *Language) runCommand(command *cmd) (string, error) {\n\tif command.getVersion == nil {\n\t\tif !l.env.HasCommand(command.executable) {\n\t\t\treturn \"\", errors.New(noVersion)\n\t\t}\n\n\t\tversionStr, err := l.env.RunCommand(command.executable, command.args...)\n\t\tif exitErr, ok := err.(*runtime.CommandError); ok {\n\t\t\tl.exitCode = exitErr.ExitCode\n\t\t\treturn \"\", fmt.Errorf(\"err executing %s with %s\", command.executable, command.args)\n\t\t}\n\n\t\treturn versionStr, nil\n\t}\n\n\tversionStr, err := command.getVersion()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif versionStr == \"\" {\n\t\treturn \"\", errors.New(\"no version found\")\n\t}\n\n\treturn versionStr, nil\n}\n\nfunc (l *Language) loadLanguageContext() {\n\tif l.loadContext == nil {\n\t\treturn\n\t}\n\tl.loadContext()\n}\n\nfunc (l *Language) inLanguageContext() bool {\n\tif l.inContext == nil {\n\t\treturn false\n\t}\n\treturn l.inContext()\n}\n\nfunc (l *Language) buildVersionURL() {\n\tversionURLTemplate := l.options.String(options.VersionURLTemplate, l.versionURLTemplate)\n\tif versionURLTemplate == \"\" {\n\t\treturn\n\t}\n\n\turl, err := template.Render(versionURLTemplate, l.Version)\n\tif err != nil {\n\t\treturn\n\t}\n\n\tl.URL = url\n}\n\nfunc (l *Language) hasNodePackage(name string) bool {\n\tpackageJSON := l.env.FileContent(\"package.json\")\n\n\tvar packageData map[string]any\n\tif err := json.Unmarshal([]byte(packageJSON), &packageData); err != nil {\n\t\treturn false\n\t}\n\n\tdependencies, ok := packageData[\"dependencies\"].(map[string]any)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif _, exists := dependencies[name]; !exists {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (l *Language) nodePackageVersion(name string) (string, error) {\n\tfolder := filepath.Join(l.env.Pwd(), \"node_modules\", name)\n\n\tconst fileName string = \"package.json\"\n\tif !l.env.HasFilesInDir(folder, fileName) {\n\t\treturn \"\", fmt.Errorf(\"%s not found in %s\", fileName, folder)\n\t}\n\n\tcontent := l.env.FileContent(filepath.Join(folder, fileName))\n\tvar data ProjectData\n\terr := json.Unmarshal([]byte(content), &data)\n\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn data.Version, nil\n}\n"
  },
  {
    "path": "src/segments/language_test.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n\t\"slices\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tuniversion = \"1.3.307\"\n\tuni        = \"*.uni\"\n\tcorn       = \"*.corn\"\n)\n\ntype languageArgs struct {\n\texpectedError      error\n\toptions            options.Provider\n\tmatchesVersionFile matchesVersionFile\n\tversion            string\n\tversionURLTemplate string\n\textensions         []string\n\tenabledExtensions  []string\n\tcommands           []*cmd\n\tenabledCommands    []string\n\tinHome             bool\n}\n\nfunc (l *languageArgs) hasvalue(value string, list []string) bool {\n\treturn slices.Contains(list, value)\n}\n\nfunc bootStrapLanguageTest(args *languageArgs) *Language {\n\tenv := new(mock.Environment)\n\n\tfor _, command := range args.commands {\n\t\tenv.On(\"HasCommand\", command.executable).Return(args.hasvalue(command.executable, args.enabledCommands))\n\t\tenv.On(\"RunCommand\", command.executable, command.args).Return(args.version, args.expectedError)\n\t}\n\n\tfor _, extension := range args.extensions {\n\t\tenv.On(\"HasFiles\", extension).Return(args.hasvalue(extension, args.enabledExtensions))\n\t}\n\n\thome := \"/usr/home\"\n\tcwd := \"/usr/home/project\"\n\tif args.inHome {\n\t\tcwd = home\n\t}\n\n\tenv.On(\"Pwd\").Return(cwd)\n\tenv.On(\"Home\").Return(home)\n\n\tif args.options == nil {\n\t\targs.options = options.Map{}\n\t}\n\n\tl := &Language{\n\t\textensions:         args.extensions,\n\t\tcommands:           args.commands,\n\t\tversionURLTemplate: args.versionURLTemplate,\n\t\tmatchesVersionFile: args.matchesVersionFile,\n\t}\n\tl.Init(args.options, env)\n\n\treturn l\n}\n\nfunc TestLanguageFilesFoundButNoCommandAndVersionAndDisplayVersion(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni},\n\t\tenabledExtensions: []string{uni},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, noVersion, lang.Error, \"unicorn is not available\")\n}\n\nfunc TestLanguageFilesFoundButNoCommandAndVersionAndDontDisplayVersion(t *testing.T) {\n\tprops := options.Map{\n\t\toptions.FetchVersion: false,\n\t}\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni},\n\t\tenabledExtensions: []string{uni},\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled(), \"unicorn is not available\")\n}\n\nfunc TestLanguageFilesFoundButNoCommandAndNoVersion(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni},\n\t\tenabledExtensions: []string{uni},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled(), \"unicorn is not available\")\n}\n\nfunc TestLanguageDisabledNoFiles(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni},\n\t\tenabledExtensions: []string{},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.False(t, lang.Enabled(), \"no files in the current directory\")\n}\n\nfunc TestLanguageEnabledOneExtensionFound(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, universion, lang.Full, \"unicorn is available and uni files are found\")\n\tassert.Equal(t, \"unicorn\", lang.Executable, \"unicorn was used\")\n}\n\nfunc TestLanguageEnabledMismatch(t *testing.T) {\n\texpectedVersion := \"1.2.009\"\n\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\tmatchesVersionFile: func() (string, bool) {\n\t\t\treturn expectedVersion, false\n\t\t},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, expectedVersion, lang.Expected, \"the expected unicorn version is 1.2.009\")\n\tassert.True(t, lang.Mismatch, \"we require a different version of unicorn\")\n}\n\nfunc TestLanguageDisabledInHome(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\tinHome:            true,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.False(t, lang.Enabled())\n}\n\nfunc TestLanguageEnabledSecondExtensionFound(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, universion, lang.Full, \"unicorn is available and corn files are found\")\n\tassert.Equal(t, \"unicorn\", lang.Executable, \"unicorn was used\")\n}\n\nfunc TestLanguageEnabledSecondCommand(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"uni\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t\t{\n\t\t\t\texecutable: \"corn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{corn},\n\t\tenabledCommands:   []string{\"corn\"},\n\t\tversion:           universion,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, universion, lang.Full, \"unicorn is available and corn files are found\")\n\tassert.Equal(t, \"corn\", lang.Executable, \"corn was used\")\n}\n\nfunc TestLanguageEnabledAllExtensionsFound(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, universion, lang.Full, \"unicorn is available and uni and corn files are found\")\n\tassert.Equal(t, \"unicorn\", lang.Executable, \"unicorn was used\")\n}\n\nfunc TestLanguageEnabledNoVersion(t *testing.T) {\n\tprops := options.Map{\n\t\toptions.FetchVersion: false,\n\t}\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"unicorn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"\", lang.Full, \"unicorn is available and uni and corn files are found\")\n\tassert.Equal(t, \"\", lang.Executable, \"no version was found\")\n}\n\nfunc TestLanguageEnabledMissingCommand(t *testing.T) {\n\tprops := options.Map{\n\t\toptions.FetchVersion: false,\n\t}\n\targs := &languageArgs{\n\t\tcommands:          []*cmd{},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"\", lang.Full, \"unicorn is unavailable and uni and corn files are found\")\n\tassert.Equal(t, \"\", lang.Executable, \"no executable was found\")\n}\n\nfunc TestLanguageEnabledNoVersionData(t *testing.T) {\n\tprops := options.Map{\n\t\toptions.FetchVersion: true,\n\t}\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"uni\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"uni\"},\n\t\tversion:           \"\",\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"\", lang.Full)\n\tassert.Equal(t, \"\", lang.Executable, \"no version was found\")\n}\n\nfunc TestLanguageEnabledMissingCommandCustomText(t *testing.T) {\n\texpected := \"missing\"\n\tprops := options.Map{\n\t\tMissingCommandText: expected,\n\t}\n\targs := &languageArgs{\n\t\tcommands:          []*cmd{},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, expected, lang.Error, \"unicorn is available and uni and corn files are found\")\n}\n\nfunc TestLanguageEnabledMissingCommandCustomTextHideError(t *testing.T) {\n\tprops := options.Map{MissingCommandText: \"missing\"}\n\targs := &languageArgs{\n\t\tcommands:          []*cmd{},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"unicorn\"},\n\t\tversion:           universion,\n\t\toptions:           props,\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"\", lang.Full)\n}\n\nfunc TestLanguageEnabledCommandExitCode(t *testing.T) {\n\texpected := 200\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"uni\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni, corn},\n\t\tenabledExtensions: []string{uni, corn},\n\t\tenabledCommands:   []string{\"uni\"},\n\t\tversion:           universion,\n\t\texpectedError:     &runtime.CommandError{ExitCode: expected},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"err executing uni with [--version]\", lang.Error)\n\tassert.Equal(t, expected, lang.exitCode)\n}\n\nfunc TestLanguageHyperlinkEnabled(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"uni\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t},\n\t\t\t{\n\t\t\t\texecutable: \"corn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t},\n\t\t},\n\t\tversionURLTemplate: \"https://unicor.org/doc/{{ .Full }}\",\n\t\textensions:         []string{uni, corn},\n\t\tenabledExtensions:  []string{corn},\n\t\tenabledCommands:    []string{\"corn\"},\n\t\tversion:            universion,\n\t\toptions:            options.Map{},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"https://unicor.org/doc/1.3.307\", lang.URL)\n}\n\nfunc TestLanguageHyperlinkEnabledWrongRegex(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable: \"uni\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `wrong`,\n\t\t\t},\n\t\t\t{\n\t\t\t\texecutable: \"corn\",\n\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\tregex:      `wrong`,\n\t\t\t},\n\t\t},\n\t\tversionURLTemplate: \"https://unicor.org/doc/{{ .Full }}\",\n\t\textensions:         []string{uni, corn},\n\t\tenabledExtensions:  []string{corn},\n\t\tenabledCommands:    []string{\"corn\"},\n\t\tversion:            universion,\n\t\toptions:            options.Map{},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"err parsing info from corn with 1.3.307\", lang.Error)\n}\n\nfunc TestLanguageEnabledInHome(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tHomeEnabled     bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{Case: \"Always enabled\", HomeEnabled: true, ExpectedEnabled: true},\n\t\t{Case: \"Context disabled\", HomeEnabled: false, ExpectedEnabled: false},\n\t}\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tHomeEnabled: tc.HomeEnabled,\n\t\t}\n\t\targs := &languageArgs{\n\t\t\tcommands: []*cmd{\n\t\t\t\t{\n\t\t\t\t\texecutable: \"uni\",\n\t\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t\t},\n\t\t\t},\n\t\t\textensions:        []string{uni, corn},\n\t\t\tenabledExtensions: []string{corn},\n\t\t\tenabledCommands:   []string{\"corn\"},\n\t\t\tversion:           universion,\n\t\t\toptions:           props,\n\t\t\tinHome:            true,\n\t\t}\n\t\tlang := bootStrapLanguageTest(args)\n\t\tassert.Equal(t, tc.ExpectedEnabled, lang.Enabled(), tc.Case)\n\t}\n}\n\nfunc TestLanguageInnerHyperlink(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable:         \"uni\",\n\t\t\t\targs:               []string{\"--version\"},\n\t\t\t\tregex:              `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t\tversionURLTemplate: \"https://uni.org/release/{{ .Full }}\",\n\t\t\t},\n\t\t\t{\n\t\t\t\texecutable:         \"corn\",\n\t\t\t\targs:               []string{\"--version\"},\n\t\t\t\tregex:              `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t\tversionURLTemplate: \"https://unicor.org/doc/{{ .Full }}\",\n\t\t\t},\n\t\t},\n\t\tversionURLTemplate: \"This gets replaced with inner template\",\n\t\textensions:         []string{uni, corn},\n\t\tenabledExtensions:  []string{corn},\n\t\tenabledCommands:    []string{\"corn\"},\n\t\tversion:            universion,\n\t\toptions:            options.Map{},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"https://unicor.org/doc/1.3.307\", lang.URL)\n}\n\nfunc TestLanguageHyperlinkTemplatePropertyTakesPriority(t *testing.T) {\n\targs := &languageArgs{\n\t\tcommands: []*cmd{\n\t\t\t{\n\t\t\t\texecutable:         \"uni\",\n\t\t\t\targs:               []string{\"--version\"},\n\t\t\t\tregex:              `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t\t\tversionURLTemplate: \"https://uni.org/release/{{ .Full }}\",\n\t\t\t},\n\t\t},\n\t\textensions:        []string{uni},\n\t\tenabledExtensions: []string{uni},\n\t\tenabledCommands:   []string{\"uni\"},\n\t\tversion:           universion,\n\t\toptions: options.Map{\n\t\t\toptions.VersionURLTemplate: \"https://custom/url/template/{{ .Major }}.{{ .Minor }}\",\n\t\t},\n\t}\n\tlang := bootStrapLanguageTest(args)\n\tassert.True(t, lang.Enabled())\n\tassert.Equal(t, \"https://custom/url/template/1.3\", lang.URL)\n}\n\nfunc TestLanguageTooling(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedFirst   string\n\t\tExpectedVersion string\n\t\tToolVersion     string\n\t\tDefaultVersion  string\n\t\tTooling         []string\n\t\tDefaultTooling  []string\n\t\tEnabledTools    []string\n\t}{\n\t\t{\n\t\t\tCase:            \"Custom tooling overrides default\",\n\t\t\tTooling:         []string{\"mytool\"},\n\t\t\tDefaultTooling:  []string{\"unicorn\"},\n\t\t\tEnabledTools:    []string{\"mytool\", \"unicorn\"},\n\t\t\tExpectedFirst:   \"mytool\",\n\t\t\tExpectedVersion: \"2.0.0\",\n\t\t\tToolVersion:     \"2.0.0\",\n\t\t\tDefaultVersion:  \"1.0.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Default tooling used when no override\",\n\t\t\tTooling:         nil,\n\t\t\tDefaultTooling:  []string{\"unicorn\"},\n\t\t\tEnabledTools:    []string{\"mytool\", \"unicorn\"},\n\t\t\tExpectedFirst:   \"unicorn\",\n\t\t\tExpectedVersion: \"1.0.0\",\n\t\t\tToolVersion:     \"2.0.0\",\n\t\t\tDefaultVersion:  \"1.0.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Tool not available falls back to next\",\n\t\t\tTooling:         []string{\"mytool\", \"unicorn\"},\n\t\t\tDefaultTooling:  []string{\"unicorn\"},\n\t\t\tEnabledTools:    []string{\"unicorn\"},\n\t\t\tExpectedFirst:   \"mytool\",\n\t\t\tExpectedVersion: \"1.0.0\",\n\t\t\tToolVersion:     \"\",\n\t\t\tDefaultVersion:  \"1.0.0\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Pwd\").Return(\"/usr/home/project\")\n\t\tenv.On(\"Home\").Return(\"/usr/home\")\n\t\tenv.On(\"HasFiles\", uni).Return(true)\n\n\t\thasUnicorn := slices.Contains(tc.EnabledTools, \"unicorn\")\n\t\tenv.On(\"HasCommand\", \"unicorn\").Return(hasUnicorn)\n\t\tif hasUnicorn {\n\t\t\tenv.On(\"RunCommand\", \"unicorn\", []string{\"--version\"}).Return(tc.DefaultVersion, nil)\n\t\t}\n\n\t\thasToolCommand := slices.Contains(tc.EnabledTools, \"mytool\")\n\t\tenv.On(\"HasCommand\", \"mytool\").Return(hasToolCommand)\n\t\tif hasToolCommand {\n\t\t\tenv.On(\"RunCommand\", \"mytool\", []string{\"--version\"}).Return(tc.ToolVersion, nil)\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\toptions.FetchVersion: true,\n\t\t}\n\t\tif tc.Tooling != nil {\n\t\t\tprops[Tooling] = tc.Tooling\n\t\t}\n\n\t\tl := &Language{\n\t\t\textensions:     []string{uni},\n\t\t\tdefaultTooling: tc.DefaultTooling,\n\t\t\ttooling: map[string]*cmd{\n\t\t\t\t\"unicorn\": {\n\t\t\t\t\texecutable: \"unicorn\",\n\t\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t\t},\n\t\t\t\t\"mytool\": {\n\t\t\t\t\texecutable: \"mytool\",\n\t\t\t\t\targs:       []string{\"--version\"},\n\t\t\t\t\tregex:      \"(?P<version>.*)\",\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\tl.Init(props, env)\n\n\t\tassert.True(t, l.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedFirst, l.commands[0].executable, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedVersion, l.Full, tc.Case)\n\t}\n}\n\ntype mockedLanguageParams struct {\n\tcmd           string\n\tversionParam  string\n\tversionOutput string\n\textension     string\n}\n\nfunc getMockedLanguageEnv(params *mockedLanguageParams) (*mock.Environment, options.Map) {\n\tenv := new(mock.Environment)\n\tenv.On(\"HasCommand\", params.cmd).Return(true)\n\tenv.On(\"RunCommand\", params.cmd, []string{params.versionParam}).Return(params.versionOutput, nil)\n\tenv.On(\"HasFiles\", params.extension).Return(true)\n\tenv.On(\"Pwd\").Return(\"/usr/home/project\")\n\tenv.On(\"Home\").Return(\"/usr/home\")\n\n\tprops := options.Map{\n\t\toptions.FetchVersion: true,\n\t}\n\n\treturn env, props\n}\n\nfunc TestNodePackageVersion(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tPackageJSON string\n\t\tVersion     string\n\t\tShouldFail  bool\n\t\tNoFiles     bool\n\t}{\n\t\t{Case: \"14.1.5\", Version: \"14.1.5\", PackageJSON: \"{ \\\"name\\\": \\\"nx\\\",\\\"version\\\": \\\"14.1.5\\\"}\"},\n\t\t{Case: \"14.0.0\", Version: \"14.0.0\", PackageJSON: \"{ \\\"name\\\": \\\"nx\\\",\\\"version\\\": \\\"14.0.0\\\"}\"},\n\t\t{Case: \"no files\", NoFiles: true, ShouldFail: true},\n\t\t{Case: \"bad data\", ShouldFail: true, PackageJSON: \"bad data\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tvar env = new(mock.Environment)\n\t\tenv.On(\"Pwd\").Return(\"posh\")\n\t\tpath := filepath.Join(\"posh\", \"node_modules\", \"nx\")\n\t\tenv.On(\"HasFilesInDir\", path, \"package.json\").Return(!tc.NoFiles)\n\t\tenv.On(\"FileContent\", filepath.Join(path, \"package.json\")).Return(tc.PackageJSON)\n\n\t\ta := &Language{}\n\t\ta.Init(options.Map{}, env)\n\t\tgot, err := a.nodePackageVersion(\"nx\")\n\n\t\tif tc.ShouldFail {\n\t\t\tassert.Error(t, err, tc.Case)\n\t\t\treturn\n\t\t}\n\n\t\tassert.Nil(t, err, tc.Case)\n\t\tassert.Equal(t, tc.Version, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/lastfm.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype LastFM struct {\n\tBase\n\n\tArtist string\n\tTrack  string\n\tFull   string\n\tIcon   string\n\tStatus string\n}\n\nconst (\n\t// LastFM username\n\tUsername options.Option = \"username\"\n)\n\ntype lmfDate struct {\n\tUnixString string `json:\"uts\"`\n}\n\ntype lfmTrackInfo struct {\n\tIsPlaying *string `json:\"nowplaying,omitempty\"`\n}\n\ntype Artist struct {\n\tName string `json:\"#text\"`\n}\n\ntype lfmTrack struct {\n\tArtist `json:\"artist\"`\n\tName   string        `json:\"name\"`\n\tInfo   *lfmTrackInfo `json:\"@attr\"`\n\tDate   lmfDate       `json:\"date\"`\n}\n\ntype tracks struct {\n\tTracks []*lfmTrack `json:\"track\"`\n}\n\ntype lfmDataResponse struct {\n\tTracksInfo tracks `json:\"recenttracks\"`\n}\n\nfunc (d *LastFM) Enabled() bool {\n\terr := d.setStatus()\n\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (d *LastFM) Template() string {\n\treturn \" {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Full }}{{ end }} \"\n}\n\nfunc (d *LastFM) getResult() (*lfmDataResponse, error) {\n\tresponse := new(lfmDataResponse)\n\n\tapikey := d.options.Template(APIKey, \".\", d)\n\tusername := d.options.Template(Username, \".\", d)\n\thttpTimeout := d.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\turl := fmt.Sprintf(\"https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&api_key=%s&user=%s&format=json&limit=1\", apikey, username)\n\n\tbody, err := d.env.HTTPRequest(url, nil, httpTimeout)\n\tif err != nil {\n\t\treturn new(lfmDataResponse), err\n\t}\n\n\terr = json.Unmarshal(body, &response)\n\tif err != nil {\n\t\treturn new(lfmDataResponse), err\n\t}\n\n\treturn response, nil\n}\n\nfunc (d *LastFM) setStatus() error {\n\tq, err := d.getResult()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(q.TracksInfo.Tracks) == 0 {\n\t\treturn errors.New(\"no data found\")\n\t}\n\n\ttrack := q.TracksInfo.Tracks[0]\n\n\td.Artist = track.Artist.Name\n\td.Track = track.Name\n\td.Full = fmt.Sprintf(\"%s - %s\", d.Artist, d.Track)\n\n\tisPlaying := track.Info != nil && track.Info.IsPlaying != nil && *track.Info.IsPlaying == \"true\"\n\n\tif isPlaying {\n\t\td.Icon = d.options.String(PlayingIcon, \"\\uE602 \")\n\t\td.Status = \"playing\"\n\t} else {\n\t\td.Icon = d.options.String(StoppedIcon, \"\\uF04D \")\n\t\td.Status = \"stopped\"\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/lastfm_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tLFMAPIURL = \"https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&api_key=key&user=KibbeWater&format=json&limit=1\"\n)\n\nfunc TestLFMSegmentSingle(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tAPIJSONResponse string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"All Defaults\",\n\t\t\tAPIJSONResponse: `{\"recenttracks\":{\"track\":[{\"artist\":{\"#text\":\"C.Gambino\"},\"name\":\"Automatic\",\"@attr\":{\"nowplaying\":\"true\"}}]}}`,\n\t\t\tExpectedString:  \"\\uE602 C.Gambino - Automatic\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Custom Template\",\n\t\t\tAPIJSONResponse: `{\"recenttracks\":{\"track\":[{\"artist\":{\"#text\":\"C.Gambino\"},\"name\":\"Automatic\",\"@attr\":{\"nowplaying\":\"true\"}}]}}`,\n\t\t\tExpectedString:  \"\\uE602 C.Gambino - Automatic\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTemplate:        \"{{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Full }}{{ end }}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Song Stopped\",\n\t\t\tAPIJSONResponse: `{\"recenttracks\":{\"track\":[{\"artist\":{\"#text\":\"C.Gambino\"},\"name\":\"Automatic\",\"date\":{\"uts\":\"1699350223\"}}]}}`,\n\t\t\tExpectedString:  \"\\uF04D\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTemplate:        \"{{ .Icon }}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Error in retrieving data\",\n\t\t\tAPIJSONResponse: \"nonsense\",\n\t\t\tError:           errors.New(\"Something went wrong\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tprops := options.Map{\n\t\t\tAPIKey:              \"key\",\n\t\t\tUsername:            \"KibbeWater\",\n\t\t\toptions.HTTPTimeout: 20000,\n\t\t}\n\n\t\tenv.On(\"HTTPRequest\", LFMAPIURL).Return([]byte(tc.APIJSONResponse), tc.Error)\n\n\t\tlfm := &LastFM{}\n\t\tlfm.Init(props, env)\n\n\t\tenabled := lfm.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = lfm.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, lfm), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/lua.go",
    "content": "package segments\n\ntype Lua struct {\n\tLanguage\n}\n\nfunc (l *Lua) Template() string {\n\treturn languageTemplate\n}\n\nfunc (l *Lua) Enabled() bool {\n\tl.extensions = []string{\"*.lua\", \"*.rockspec\"}\n\tl.folders = []string{\"lua\"}\n\tl.tooling = map[string]*cmd{\n\t\t\"lua\": {\n\t\t\texecutable:         \"lua\",\n\t\t\targs:               []string{\"-v\"},\n\t\t\tregex:              `Lua (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)(.(?P<patch>[0-9]+))?))`,\n\t\t\tversionURLTemplate: \"https://www.lua.org/manual/{{ .Major }}.{{ .Minor }}/readme.html#changes\",\n\t\t},\n\t\t\"luajit\": {\n\t\t\texecutable:         \"luajit\",\n\t\t\targs:               []string{\"-v\"},\n\t\t\tregex:              `LuaJIT (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)(.(?P<patch>[0-9]+))?))`,\n\t\t\tversionURLTemplate: \"https://github.com/LuaJIT/LuaJIT/tree/v{{ .Major}}.{{ .Minor}}\",\n\t\t},\n\t}\n\tl.defaultTooling = []string{\"lua\", \"luajit\"}\n\n\treturn l.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/lua_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestLua(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t\tExpectedURL    string\n\t\tTooling        []string\n\t\tHasLua         bool\n\t\tHasLuaJit      bool\n\t}{\n\t\t{\n\t\t\tCase:           \"Lua 5.4.4 - default tooling prefers lua\",\n\t\t\tExpectedString: \"5.4.4\",\n\t\t\tVersion:        \"Lua 5.4.4  Copyright (C) 1994-2022 Lua.org, PUC-Rio\",\n\t\t\tExpectedURL:    \"https://www.lua.org/manual/5.4/readme.html#changes\",\n\t\t\tHasLua:         true,\n\t\t\tHasLuaJit:      true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Lua 5.0 - tooling set to luajit but missing so fallback to lua\",\n\t\t\tExpectedString: \"5.0\",\n\t\t\tVersion:        \"Lua 5.0  Copyright (C) 1994-2003 Tecgraf, PUC-Rio\",\n\t\t\tExpectedURL:    \"https://www.lua.org/manual/5.0/readme.html#changes\",\n\t\t\tHasLua:         true,\n\t\t\tTooling:        []string{\"luajit\", \"lua\"},\n\t\t},\n\t\t{\n\t\t\tCase:           \"LuaJIT 2.0.5 - tooling set to luajit first\",\n\t\t\tExpectedString: \"2.0.5\",\n\t\t\tVersion:        \"LuaJIT 2.0.5 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/\",\n\t\t\tHasLuaJit:      true,\n\t\t\tHasLua:         true,\n\t\t\tExpectedURL:    \"https://github.com/LuaJIT/LuaJIT/tree/v2.0\",\n\t\t\tTooling:        []string{\"luajit\"},\n\t\t},\n\t\t{\n\t\t\tCase:           \"LuaJIT 2.1.0-beta3 - tooling set to lua first but missing so try luajit\",\n\t\t\tExpectedString: \"2.1.0\",\n\t\t\tVersion:        \"LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/\",\n\t\t\tHasLuaJit:      true,\n\t\t\tExpectedURL:    \"https://github.com/LuaJIT/LuaJIT/tree/v2.1\",\n\t\t\tTooling:        []string{\"lua\", \"luajit\"},\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"lua\",\n\t\t\tversionParam:  \"-v\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.lua\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif !tc.HasLua {\n\t\t\tenv.Unset(\"HasCommand\")\n\t\t\tenv.On(\"HasCommand\", \"lua\").Return(false)\n\t\t}\n\n\t\tenv.On(\"HasCommand\", \"luajit\").Return(tc.HasLuaJit)\n\t\tenv.On(\"RunCommand\", \"luajit\", []string{\"-v\"}).Return(tc.Version, nil)\n\t\tenv.On(\"Shell\").Return(\"bash\")\n\n\t\t// Initialize template system for version URL rendering\n\t\tif template.Cache == nil {\n\t\t\ttemplate.Cache = &cache.Template{}\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tif len(tc.Tooling) > 0 {\n\t\t\tprops[Tooling] = tc.Tooling\n\t\t}\n\n\t\tl := &Lua{}\n\t\tl.Init(props, env)\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, l.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, l.Template(), l), failMsg)\n\t\tassert.Equal(t, tc.ExpectedURL, l.URL, failMsg)\n\t}\n}\n"
  },
  {
    "path": "src/segments/mercurial.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\nconst (\n\tMERCURIALCOMMAND = \"hg\"\n\n\thgLogTemplate = \"{rev}|{node}|{branch}|{tags}|{bookmarks}\"\n)\n\ntype MercurialStatus struct {\n\tScmStatus\n}\n\nfunc (s *MercurialStatus) add(code string) {\n\tswitch code {\n\tcase \"R\", \"!\":\n\t\ts.Deleted++\n\tcase \"A\":\n\t\ts.Added++\n\tcase \"?\":\n\t\ts.Untracked++\n\tcase \"M\":\n\t\ts.Modified++\n\t}\n}\n\ntype Mercurial struct {\n\tWorking           *MercurialStatus\n\tLocalCommitNumber string\n\tChangeSetID       string\n\tChangeSetIDShort  string\n\tBranch            string\n\tScm\n\tBookmarks []string\n\tTags      []string\n\tIsTip     bool\n}\n\nfunc (hg *Mercurial) Template() string {\n\treturn \"hg {{.Branch}} {{if .LocalCommitNumber}}({{.LocalCommitNumber}}:{{.ChangeSetIDShort}}){{end}}{{range .Bookmarks }} \\uf02e {{.}}{{end}}{{range .Tags}} \\uf02b {{.}}{{end}}{{if .Working.Changed}} \\uf044 {{ .Working.String }}{{ end }}\" //nolint: lll\n}\n\nfunc (hg *Mercurial) Enabled() bool {\n\tif !hg.shouldDisplay() {\n\t\treturn false\n\t}\n\n\tstatusFormats := hg.options.KeyValueMap(StatusFormats, map[string]string{})\n\thg.Working = &MercurialStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\tdisplayStatus := hg.options.Bool(FetchStatus, false)\n\tif displayStatus {\n\t\thg.setMercurialStatus()\n\t}\n\n\treturn true\n}\n\nfunc (hg *Mercurial) CacheKey() (string, bool) {\n\tdir, err := hg.env.HasParentFilePath(\".hg\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn dir.Path, true\n}\n\nfunc (hg *Mercurial) shouldDisplay() bool {\n\tif !hg.hasCommand(MERCURIALCOMMAND) {\n\t\treturn false\n\t}\n\n\thgdir, err := hg.env.HasParentFilePath(\".hg\", false)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\thg.setDir(hgdir.ParentFolder)\n\n\thg.mainSCMDir = hgdir.Path\n\thg.scmDir = hgdir.Path\n\t// convert the worktree file path to a windows one when in a WSL shared folder\n\thg.repoRootDir = strings.TrimSuffix(hg.convertToWindowsPath(hgdir.Path), \"/.hg\")\n\treturn true\n}\n\nfunc (hg *Mercurial) setDir(dir string) {\n\tdir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD\n\tif hg.env.GOOS() == runtime.WINDOWS {\n\t\thg.Dir = strings.TrimSuffix(dir, `\\.hg`)\n\t\treturn\n\t}\n\thg.Dir = strings.TrimSuffix(dir, \"/.hg\")\n}\n\nfunc (hg *Mercurial) setMercurialStatus() {\n\thg.Branch = hg.command\n\n\tidString := hg.getHgCommandOutput(\"log\", \"-r\", \".\", \"--template\", hgLogTemplate)\n\tif idString == \"\" {\n\t\treturn\n\t}\n\n\tidSplit := strings.SplitN(idString, \"|\", 6)\n\tif len(idSplit) != 5 {\n\t\treturn\n\t}\n\n\thg.LocalCommitNumber = idSplit[0]\n\thg.ChangeSetID = idSplit[1]\n\n\tif len(hg.ChangeSetID) >= 12 {\n\t\thg.ChangeSetIDShort = hg.ChangeSetID[:12]\n\t}\n\thg.Branch = idSplit[2]\n\n\thg.Tags = doSplit(idSplit[3])\n\thg.Bookmarks = doSplit(idSplit[4])\n\n\thg.IsTip = false\n\ttipIndex := 0\n\tfor i, tag := range hg.Tags {\n\t\tif tag == \"tip\" {\n\t\t\thg.IsTip = true\n\t\t\ttipIndex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif hg.IsTip {\n\t\thg.Tags = RemoveAtIndex(hg.Tags, tipIndex)\n\t}\n\n\tstatusString := hg.getHgCommandOutput(\"status\")\n\n\tif statusString == \"\" {\n\t\treturn\n\t}\n\n\tstatusLines := strings.SplitSeq(statusString, \"\\n\")\n\n\tfor status := range statusLines {\n\t\thg.Working.add(status[:1])\n\t}\n}\n\nfunc doSplit(s string) []string {\n\tif s == \"\" {\n\t\treturn []string{}\n\t}\n\n\treturn strings.Split(s, \" \")\n}\n\nfunc RemoveAtIndex(s []string, index int) []string {\n\tret := make([]string, 0)\n\tret = append(ret, s[:index]...)\n\treturn append(ret, s[index+1:]...)\n}\n\nfunc (hg *Mercurial) getHgCommandOutput(command string, args ...string) string {\n\targs = append([]string{\"-R\", hg.repoRootDir, command}, args...)\n\tval, err := hg.env.RunCommand(hg.command, args...)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSpace(val)\n}\n"
  },
  {
    "path": "src/segments/mercurial_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestMercurialEnabledToolNotFound(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"hg\").Return(false)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\n\thg := &Mercurial{}\n\thg.Init(options.Map{}, env)\n\n\tassert.False(t, hg.Enabled())\n}\n\nfunc TestMercurialEnabledInWorkingDirectory(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/hello\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"hg\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"HasParentFilePath\", \".hg\", false).Return(fileInfo, nil)\n\tenv.On(\"PathSeparator\").Return(\"/\")\n\tenv.On(\"Home\").Return(poshHome)\n\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\n\thg := &Mercurial{}\n\thg.Init(options.Map{}, env)\n\n\tassert.True(t, hg.Enabled())\n\tassert.Equal(t, fileInfo.Path, hg.mainSCMDir)\n\tassert.Equal(t, fileInfo.Path, hg.repoRootDir)\n}\n\nfunc TestMercurialGetIdInfo(t *testing.T) {\n\tcases := []struct {\n\t\tExpectedWorking           *MercurialStatus\n\t\tCase                      string\n\t\tLogOutput                 string\n\t\tStatusOutput              string\n\t\tExpectedBranch            string\n\t\tExpectedChangeSetID       string\n\t\tExpectedShortID           string\n\t\tExpectedLocalCommitNumber string\n\t\tExpectedBookmarks         []string\n\t\tExpectedTags              []string\n\t\tExpectedIsTip             bool\n\t}{\n\t\t{\n\t\t\tCase:         \"nochanges_tip\",\n\t\t\tLogOutput:    \"123|b6cb23dcb79fe5c2215f1ae8f1a85326a7fed500|branchname|tip|\",\n\t\t\tStatusOutput: \"\",\n\t\t\tExpectedWorking: &MercurialStatus{ScmStatus{\n\t\t\t\tModified:   0,\n\t\t\t\tAdded:      0,\n\t\t\t\tDeleted:    0,\n\t\t\t\tMoved:      0,\n\t\t\t\tUntracked:  0,\n\t\t\t\tConflicted: 0,\n\t\t\t}},\n\t\t\tExpectedBranch:            \"branchname\",\n\t\t\tExpectedChangeSetID:       \"b6cb23dcb79fe5c2215f1ae8f1a85326a7fed500\",\n\t\t\tExpectedShortID:           \"b6cb23dcb79f\",\n\t\t\tExpectedLocalCommitNumber: \"123\",\n\t\t\tExpectedIsTip:             true,\n\t\t\tExpectedBookmarks:         []string{},\n\t\t\tExpectedTags:              []string{},\n\t\t},\n\t\t{\n\t\t\tCase:         \"nochanges\",\n\t\t\tLogOutput:    \"123|b6cb23dcb79fe5c2215f1ae8f1a85326a7fed500|branchname||\",\n\t\t\tStatusOutput: \"\",\n\t\t\tExpectedWorking: &MercurialStatus{ScmStatus{\n\t\t\t\tModified:   0,\n\t\t\t\tAdded:      0,\n\t\t\t\tDeleted:    0,\n\t\t\t\tMoved:      0,\n\t\t\t\tUntracked:  0,\n\t\t\t\tConflicted: 0,\n\t\t\t}},\n\t\t\tExpectedBranch:            \"branchname\",\n\t\t\tExpectedChangeSetID:       \"b6cb23dcb79fe5c2215f1ae8f1a85326a7fed500\",\n\t\t\tExpectedShortID:           \"b6cb23dcb79f\",\n\t\t\tExpectedLocalCommitNumber: \"123\",\n\t\t\tExpectedIsTip:             false,\n\t\t\tExpectedBookmarks:         []string{},\n\t\t\tExpectedTags:              []string{},\n\t\t},\n\t\t{\n\t\t\tCase:      \"changed\",\n\t\t\tLogOutput: \"3|11a953bf0288663b530dd6d65f3c8e0d5f7fddb5|default|tip mytag mytag2|bm1 bm2\",\n\t\t\tStatusOutput: `\nM Modified.File\n? Untracked.File\nR Removed.File\n! AlsoRemoved.File\nA Added.File\n`,\n\t\t\tExpectedWorking: &MercurialStatus{ScmStatus{\n\t\t\t\tModified:   1,\n\t\t\t\tAdded:      1,\n\t\t\t\tDeleted:    2,\n\t\t\t\tMoved:      0,\n\t\t\t\tUntracked:  1,\n\t\t\t\tConflicted: 0,\n\t\t\t}},\n\t\t\tExpectedBranch:            \"default\",\n\t\t\tExpectedChangeSetID:       \"11a953bf0288663b530dd6d65f3c8e0d5f7fddb5\",\n\t\t\tExpectedShortID:           \"11a953bf0288\",\n\t\t\tExpectedLocalCommitNumber: \"3\",\n\t\t\tExpectedIsTip:             true,\n\t\t\tExpectedBookmarks:         []string{\"bm1\", \"bm2\"},\n\t\t\tExpectedTags:              []string{\"mytag\", \"mytag2\"},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tfileInfo := &runtime.FileInfo{\n\t\t\tPath:         \"/dir/hello\",\n\t\t\tParentFolder: \"/dir\",\n\t\t\tIsDir:        true,\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"HasCommand\", \"hg\").Return(true)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"HasParentFilePath\", \".hg\", false).Return(fileInfo, nil)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Home\").Return(poshHome)\n\t\tenv.On(\"Getenv\", poshGitEnv).Return(\"\")\n\t\tenv.MockHgCommand(fileInfo.Path, tc.LogOutput, \"log\", \"-r\", \".\", \"--template\", hgLogTemplate)\n\t\tenv.MockHgCommand(fileInfo.Path, tc.StatusOutput, \"status\")\n\n\t\thg := &Mercurial{}\n\t\thg.Init(props, env)\n\n\t\tif tc.ExpectedWorking != nil {\n\t\t\ttc.ExpectedWorking.Formats = map[string]string{}\n\t\t}\n\n\t\tassert.True(t, hg.Enabled())\n\t\tassert.Equal(t, fileInfo.Path, hg.mainSCMDir)\n\t\tassert.Equal(t, fileInfo.Path, hg.repoRootDir)\n\t\tassert.Equal(t, tc.ExpectedWorking, hg.Working, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBranch, hg.Branch, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedChangeSetID, hg.ChangeSetID, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedShortID, hg.ChangeSetIDShort, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedLocalCommitNumber, hg.LocalCommitNumber, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedIsTip, hg.IsTip, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBookmarks, hg.Bookmarks, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedTags, hg.Tags, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/mojo.go",
    "content": "package segments\n\nimport (\n\t\"slices\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Mojo struct {\n\tVenv string\n\tLanguage\n}\n\nfunc (m *Mojo) Template() string {\n\treturn \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \"\n}\n\nfunc (m *Mojo) Enabled() bool {\n\tm.extensions = []string{\"*.🔥\", \"*.mojo\", \"mojoproject.toml\"}\n\tm.tooling = map[string]*cmd{\n\t\t\"mojo\": {\n\t\t\texecutable: \"mojo\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:mojo (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tm.defaultTooling = []string{\"mojo\"}\n\tm.displayMode = m.options.String(DisplayMode, DisplayModeEnvironment)\n\tm.Language.loadContext = m.loadContext\n\tm.Language.inContext = m.inContext\n\n\treturn m.Language.Enabled()\n}\n\nfunc (m *Mojo) loadContext() {\n\tif !m.options.Bool(FetchVirtualEnv, true) {\n\t\treturn\n\t}\n\n\t// Magic, the official package manager and virtual env manager,\n\t// is built on top of pixi: https://github.com/prefix-dev/pixi\n\tvenv := m.env.Getenv(\"PIXI_ENVIRONMENT_NAME\")\n\tif len(venv) > 0 && m.canUseVenvName(venv) {\n\t\tm.Venv = venv\n\t}\n}\n\nfunc (m *Mojo) inContext() bool {\n\treturn m.Venv != \"\"\n}\n\nfunc (m *Mojo) canUseVenvName(name string) bool {\n\tdefaultNames := []string{\"default\"}\n\n\tif m.options.Bool(options.DisplayDefault, true) ||\n\t\t!slices.Contains(defaultNames, name) {\n\t\treturn true\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/mojo_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nfunc TestMojoTemplate(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpected        string\n\t\tVirtualEnvName  string\n\t\tFetchVirtualEnv bool\n\t\tDisplayDefault  bool\n\t\tFetchVersion    bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Virtual environment is present\",\n\t\t\tExpected:        \"foo 24.5.0\",\n\t\t\tVirtualEnvName:  \"foo\",\n\t\t\tFetchVirtualEnv: true,\n\t\t\tDisplayDefault:  true,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"No virtual environment present\",\n\t\t\tExpected:        \"24.5.0\",\n\t\t\tVirtualEnvName:  \"\",\n\t\t\tFetchVirtualEnv: true,\n\t\t\tDisplayDefault:  true,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Hide the virtual environment, but show the version\",\n\t\t\tExpected:        \"24.5.0\",\n\t\t\tVirtualEnvName:  \"foo\",\n\t\t\tFetchVirtualEnv: false,\n\t\t\tDisplayDefault:  true,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Show the virtual environment, but hide the version\",\n\t\t\tExpected:        \"foo\",\n\t\t\tVirtualEnvName:  \"foo\",\n\t\t\tFetchVirtualEnv: true,\n\t\t\tDisplayDefault:  true,\n\t\t\tFetchVersion:    false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Show the default virtual environment\",\n\t\t\tExpected:        \"default 24.5.0\",\n\t\t\tVirtualEnvName:  \"default\",\n\t\t\tFetchVirtualEnv: true,\n\t\t\tDisplayDefault:  true,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Hide the default virtual environment\",\n\t\t\tExpected:        \"24.5.0\",\n\t\t\tVirtualEnvName:  \"default\",\n\t\t\tFetchVirtualEnv: true,\n\t\t\tDisplayDefault:  false,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"mojo\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: \"mojo 24.5.0 (e8aacb95)\",\n\t\t\textension:     \"*.mojo\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tenv.On(\"Getenv\", \"PIXI_ENVIRONMENT_NAME\").Return(tc.VirtualEnvName)\n\t\tprops[options.DisplayDefault] = tc.DisplayDefault\n\t\tprops[options.FetchVersion] = tc.FetchVersion\n\t\tprops[FetchVirtualEnv] = tc.FetchVirtualEnv\n\t\tprops[DisplayMode] = DisplayModeAlways\n\n\t\tmojo := &Mojo{}\n\t\tmojo.Init(props, env)\n\t\tassert.True(t, mojo.Enabled())\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, mojo.Template(), mojo), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/mvn.go",
    "content": "package segments\n\ntype Mvn struct {\n\tLanguage\n}\n\nfunc (m *Mvn) Enabled() bool {\n\tm.extensions = []string{\"pom.xml\"}\n\tm.tooling = map[string]*cmd{\n\t\t\"mvn\": {\n\t\t\texecutable: \"mvn\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)(?:-(?P<prerelease>[a-z]+-[0-9]+))?))`,\n\t\t},\n\t}\n\tm.defaultTooling = []string{\"mvn\"}\n\tm.versionURLTemplate = \"https://github.com/apache/maven/releases/tag/maven-{{ .Full }}\"\n\n\tmvnw, err := m.env.HasParentFilePath(\"mvnw\", false)\n\tif err == nil {\n\t\tm.tooling[\"mvn\"].executable = mvnw.Path\n\t}\n\n\treturn m.Language.Enabled()\n}\n\nfunc (m *Mvn) Template() string {\n\treturn languageTemplate\n}\n"
  },
  {
    "path": "src/segments/mvn_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestMvn(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tMvnVersion     string\n\t\tMvnwVersion    string\n\t\tHasMvnw        bool\n\t}{\n\t\t{\n\t\t\tCase:           \"Maven version\",\n\t\t\tExpectedString: \"1.0.0\",\n\t\t\tMvnVersion:     \"Apache Maven 1.0.0\",\n\t\t\tHasMvnw:        false,\n\t\t\tMvnwVersion:    \"\"},\n\t\t{\n\t\t\tCase:           \"Local Maven version from wrapper\",\n\t\t\tExpectedString: \"1.1.0-beta-9\",\n\t\t\tMvnVersion:     \"Apache Maven 1.0.0\",\n\t\t\tHasMvnw:        true,\n\t\t\tMvnwVersion:    \"Apache Maven 1.1.0-beta-9\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"mvn\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.MvnVersion,\n\t\t\textension:     \"pom.xml\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tfileInfo := &runtime.FileInfo{\n\t\t\tPath:         \"../mvnw\",\n\t\t\tParentFolder: \"./\",\n\t\t\tIsDir:        false,\n\t\t}\n\t\tvar err error\n\t\tif !tc.HasMvnw {\n\t\t\terr = errors.New(\"no match\")\n\t\t}\n\t\tenv.On(\"HasParentFilePath\", \"mvnw\", false).Return(fileInfo, err)\n\t\tenv.On(\"HasCommand\", fileInfo.Path).Return(tc.HasMvnw)\n\t\tenv.On(\"RunCommand\", fileInfo.Path, []string{\"--version\"}).Return(tc.MvnwVersion, nil)\n\n\t\tm := &Mvn{}\n\t\tm.Init(props, env)\n\t\tassert.True(t, m.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, m.Template(), m), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/nba.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// segment struct, makes templating easier\ntype Nba struct {\n\tBase\n\n\tNBAData\n}\n\n// NBA struct contains parsed API data that care about for the segment\ntype NBAData struct {\n\tHomeTeam       string\n\tAwayTeam       string\n\tTime           string\n\tGameDate       string\n\tStartTimeUTC   string\n\tGameStatus     GameStatus // 1 = scheduled, 2 = in progress, 3 = finished\n\tHomeScore      int\n\tAwayScore      int\n\tHomeTeamWins   int\n\tHomeTeamLosses int\n\tAwayTeamWins   int\n\tAwayTeamLosses int\n}\n\nfunc (nba *NBAData) HasStats() bool {\n\treturn nba.HomeTeamWins != 0 || nba.HomeTeamLosses != 0 || nba.AwayTeamWins != 0 || nba.AwayTeamLosses != 0\n}\n\nfunc (nba *NBAData) Started() bool {\n\treturn nba.GameStatus == InProgress || nba.GameStatus == Finished\n}\n\nconst (\n\tNBASeason  options.Option = \"season\"\n\tTeamName   options.Option = \"team\"\n\tDaysOffset options.Option = \"days_offset\"\n\n\tScheduledTemplate  options.Option = \"scheduled_template\"\n\tInProgressTemplate options.Option = \"in_progress_template\"\n\tFinishedTemplate   options.Option = \"finished_template\"\n\n\tNBAScoreURL    string = \"https://cdn.nba.com/static/json/liveData/scoreboard/todaysScoreboard_00.json\"\n\tNBAScheduleURL string = \"https://stats.nba.com/stats/internationalbroadcasterschedule?LeagueID=00&Season=%s&Date=%s&RegionID=1&EST=Y\"\n\n\tUNKNOWN = \"unknown\"\n\n\tcurrentNBASeason = \"2023\"\n\tNBADateFormat    = \"02/01/2006\"\n)\n\n// Custom type for GameStatus\ntype GameStatus int\n\n// Constants for GameStatus values\nconst (\n\tScheduled  GameStatus = 1\n\tInProgress GameStatus = 2\n\tFinished   GameStatus = 3\n\tNotFound   GameStatus = 4\n)\n\n// Int() method for GameStatus to get its integer representation\n// This is a helpful method if people want to come up with their own templates\nfunc (gs GameStatus) Int() int {\n\treturn int(gs)\n}\n\nfunc (gs GameStatus) Valid() bool {\n\treturn gs == Scheduled || gs == InProgress || gs == Finished\n}\n\nfunc (gs GameStatus) String() string {\n\tswitch gs {\n\tcase Scheduled:\n\t\treturn \"Scheduled\"\n\tcase InProgress:\n\t\treturn \"In Progress\"\n\tcase Finished:\n\t\treturn \"Finished\"\n\tcase NotFound:\n\t\treturn \"Not Found\"\n\tdefault:\n\t\treturn UNKNOWN\n\t}\n}\n\n// All of the structs needed to retrieve data from the live score endpoint\ntype ScoreboardResponse struct {\n\tScoreboard Scoreboard `json:\"scoreboard\"`\n}\n\ntype Scoreboard struct {\n\tGameDate string `json:\"gameDate\"`\n\tGames    []Game `json:\"games\"`\n}\n\ntype Game struct {\n\tGameStatusText string `json:\"gameStatusText\"`\n\tGameTimeUTC    string `json:\"gameTimeUTC\"`\n\tHomeTeam       Team   `json:\"homeTeam\"`\n\tAwayTeam       Team   `json:\"awayTeam\"`\n\tGameStatus     int    `json:\"gameStatus\"`\n}\n\ntype Team struct {\n\tTeamTricode string `json:\"teamTricode\"`\n\tWins        int    `json:\"wins\"`\n\tLosses      int    `json:\"losses\"`\n\tScore       int    `json:\"score\"`\n}\n\n// All the structs needed to get data from the schedule endpoint\ntype ScheduleResponse struct {\n\tResultSets []ResultSet `json:\"resultSets\"`\n}\n\ntype ResultSet struct {\n\tCompleteGameList []ScheduledGame `json:\"CompleteGameList,omitempty\"`\n}\n\ntype ScheduledGame struct {\n\tVtAbbreviation string `json:\"vtAbbreviation\"`\n\tHtAbbreviation string `json:\"htAbbreviation\"`\n\tDate           string `json:\"date\"`\n\tTime           string `json:\"time\"`\n}\n\nfunc (nba *Nba) Template() string {\n\treturn \" \\U000F0806 {{ .HomeTeam}}{{ if .HasStats }} ({{.HomeTeamWins}}-{{.HomeTeamLosses}}){{ end }}{{ if .Started }}:{{.HomeScore}}{{ end }} vs {{ .AwayTeam}}{{ if .HasStats }} ({{.AwayTeamWins}}-{{.AwayTeamLosses}}){{ end }}{{ if .Started }}:{{.AwayScore}}{{ end }} | {{ if not .Started }}{{.GameDate}} | {{ end }}{{.Time}} \" //nolint:lll\n}\n\nfunc (nba *Nba) Enabled() bool {\n\tdata, err := nba.getResult()\n\tif err != nil || !data.GameStatus.Valid() {\n\t\treturn false\n\t}\n\n\tnba.NBAData = *data\n\n\treturn true\n}\n\n// parses through a set of games from the score endpoint and looks for props.team in away or home team\nfunc (nba *Nba) findGameScoreByTeamTricode(games []Game, teamTricode string) (*Game, error) {\n\tfor _, game := range games {\n\t\tif game.HomeTeam.TeamTricode == teamTricode || game.AwayTeam.TeamTricode == teamTricode {\n\t\t\treturn &game, nil\n\t\t}\n\t}\n\n\treturn nil, errors.New(\"no game score found for team\")\n}\n\n// parses through a set of games from the schedule endpoint and looks for props.team in away or home team\nfunc (nba *Nba) findGameSchedulebyTeamTricode(games []ScheduledGame, teamTricode string) (*ScheduledGame, error) {\n\tfor _, game := range games {\n\t\tif game.VtAbbreviation == teamTricode || game.HtAbbreviation == teamTricode {\n\t\t\treturn &game, nil\n\t\t}\n\t}\n\n\treturn nil, errors.New(\"no scheduled game found for team\")\n}\n\n// parses the time and date from the schedule endpoint into a UTC time\nfunc (nba *Nba) parseTimetoUTC(timeEST, date string) string {\n\tcombinedTime := date + \" \" + timeEST\n\ttimeUTC, err := time.Parse(\"01/02/2006 03:04 PM\", combinedTime)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\n\treturn timeUTC.UTC().Format(\"2006-01-02T15:04:05Z\")\n}\n\n// retrieves data from the score endpoint\nfunc (nba *Nba) retrieveScoreData(teamName string, httpTimeout int) (*NBAData, error) {\n\tbody, err := nba.env.HTTPRequest(NBAScoreURL, nil, httpTimeout)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar scoreboardResponse ScoreboardResponse\n\terr = json.Unmarshal(body, &scoreboardResponse)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tgameInfo, err := nba.findGameScoreByTeamTricode(scoreboardResponse.Scoreboard.Games, teamName)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &NBAData{\n\t\tAwayTeam:       gameInfo.AwayTeam.TeamTricode,\n\t\tHomeTeam:       gameInfo.HomeTeam.TeamTricode,\n\t\tTime:           gameInfo.GameStatusText,\n\t\tGameDate:       scoreboardResponse.Scoreboard.GameDate,\n\t\tStartTimeUTC:   gameInfo.GameTimeUTC,\n\t\tGameStatus:     GameStatus(gameInfo.GameStatus),\n\t\tHomeScore:      gameInfo.HomeTeam.Score,\n\t\tAwayScore:      gameInfo.AwayTeam.Score,\n\t\tHomeTeamWins:   gameInfo.HomeTeam.Wins,\n\t\tHomeTeamLosses: gameInfo.HomeTeam.Losses,\n\t\tAwayTeamWins:   gameInfo.AwayTeam.Wins,\n\t\tAwayTeamLosses: gameInfo.AwayTeam.Losses,\n\t}, nil\n}\n\n// Retrieves the data from the schedule endpoint\nfunc (nba *Nba) retrieveScheduleData(teamName string, httpTimeout int) (*NBAData, error) {\n\t// How many days into the future should we look for a game.\n\tnumDaysToSearch := nba.options.Int(DaysOffset, 8)\n\tnbaSeason := nba.options.String(NBASeason, currentNBASeason)\n\t// Get the current date in America/New_York\n\tnowNYC := time.Now().In(time.FixedZone(\"America/New_York\", -5*60*60))\n\n\t// Check to see if a game is scheduled while the numDaysToSearch is greater than 0\n\tfor numDaysToSearch > 0 {\n\t\tdateStr := nowNYC.Format(NBADateFormat)\n\t\turlEndpoint := fmt.Sprintf(NBAScheduleURL, nbaSeason, dateStr)\n\n\t\tbody, err := nba.env.HTTPRequest(urlEndpoint, nil, httpTimeout)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar scheduleResponse *ScheduleResponse\n\t\terr = json.Unmarshal(body, &scheduleResponse)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Check if we can find a game for the team\n\t\tgameInfo, err := nba.findGameSchedulebyTeamTricode(scheduleResponse.ResultSets[1].CompleteGameList, teamName)\n\t\tif err != nil {\n\t\t\t// We didn't find a game for the team on this day, so we need to check the next day\n\t\t\tnowNYC = nowNYC.AddDate(0, 0, 1)\n\t\t\tnumDaysToSearch--\n\t\t\tcontinue\n\t\t}\n\n\t\treturn &NBAData{\n\t\t\tAwayTeam:       gameInfo.VtAbbreviation,\n\t\t\tHomeTeam:       gameInfo.HtAbbreviation,\n\t\t\tTime:           gameInfo.Time + \" ET\",\n\t\t\tGameDate:       gameInfo.Date,\n\t\t\tStartTimeUTC:   nba.parseTimetoUTC(gameInfo.Time, gameInfo.Date),\n\t\t\tGameStatus:     Scheduled,\n\t\t\tHomeScore:      0,\n\t\t\tAwayScore:      0,\n\t\t\tHomeTeamWins:   0,\n\t\t\tHomeTeamLosses: 0,\n\t\t\tAwayTeamWins:   0,\n\t\t\tAwayTeamLosses: 0,\n\t\t}, nil\n\t}\n\n\treturn nil, errors.New(\"no scheduled game found for team within DaysOffset days\")\n}\n\n// First try to get the data from the score endpoint, if that fails, try the schedule endpoint\n// The score endpoint usually goes live within 12 hours of a game starting\nfunc (nba *Nba) getAvailableGameData(teamName string, httpTimeout int) (*NBAData, error) {\n\t// Get the info from the score endpoint\n\tdata, err := nba.retrieveScoreData(teamName, httpTimeout)\n\tif err == nil {\n\t\treturn data, nil\n\t}\n\n\t// If the score endpoint doesn't have anything get data from the schedule endpoint\n\tdata, err = nba.retrieveScheduleData(teamName, httpTimeout)\n\tif err == nil {\n\t\treturn data, nil\n\t}\n\n\treturn nil, err\n}\n\nfunc (nba *Nba) getResult() (*NBAData, error) {\n\tteamName := nba.options.String(TeamName, \"\")\n\n\thttpTimeout := nba.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tlog.Debug(\"fetching available data for \" + teamName)\n\n\tdata, err := nba.getAvailableGameData(teamName, httpTimeout)\n\tif err != nil {\n\t\tlog.Error(errors.Join(err, fmt.Errorf(\"unable to get data for team %s\", teamName)))\n\t\treturn nil, err\n\t}\n\n\tif !data.GameStatus.Valid() {\n\t\terr := fmt.Errorf(\"%d is not a valid game status\", data.GameStatus)\n\t\tlog.Error(err)\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "src/segments/nba_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc getTestData(file string) string {\n\tcontent, _ := os.ReadFile(fmt.Sprintf(\"../test/%s\", file))\n\treturn string(content)\n}\n\n// create Test segment for NBA segment\nfunc TestNBASegment(t *testing.T) {\n\tjsonScheduleData := getTestData(\"nba/schedule.json\")\n\tjsonScoreData := getTestData(\"nba/score.json\")\n\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tJSONResponse    string\n\t\tExpectedString  string\n\t\tTeamName        string\n\t\tCacheTimeout    int\n\t\tDaysOffset      int\n\t\tExpectedEnabled bool\n\t\tCacheFoundFail  bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Team (Home Team) Scheduled Game\",\n\t\t\tJSONResponse:    jsonScheduleData,\n\t\t\tTeamName:        \"LAL\",\n\t\t\tExpectedString:  \"󰠆 LAL vs PHX | 10/26/2023 | 10:00 PM ET\",\n\t\t\tExpectedEnabled: true,\n\t\t\tDaysOffset:      8,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Team (Away Team) Scheduled Game\",\n\t\t\tJSONResponse:    jsonScheduleData,\n\t\t\tTeamName:        \"PHX\",\n\t\t\tExpectedString:  \"󰠆 LAL vs PHX | 10/26/2023 | 10:00 PM ET\",\n\t\t\tDaysOffset:      4,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Team (Home Team) Live Game\",\n\t\t\tJSONResponse:    jsonScoreData,\n\t\t\tTeamName:        \"CHA\",\n\t\t\tExpectedString:  \"󰠆 CHA (1-0):13 vs BOS (0-1):8 | Q1 8:23\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Team (Away Team) Live Game\",\n\t\t\tJSONResponse:    jsonScoreData,\n\t\t\tTeamName:        \"BOS\",\n\t\t\tExpectedString:  \"󰠆 CHA (1-0):13 vs BOS (0-1):8 | Q1 8:23\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Team not Found\",\n\t\t\tJSONResponse:    jsonScheduleData,\n\t\t\tDaysOffset:      8,\n\t\t\tTeamName:        \"INVALID\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tprops := options.Map{\n\t\t\tTeamName:   tc.TeamName,\n\t\t\tDaysOffset: tc.DaysOffset,\n\t\t}\n\n\t\tenv.On(\"HTTPRequest\", NBAScoreURL).Return([]byte(tc.JSONResponse), tc.Error)\n\n\t\t// Add all the daysOffset to the http request responses\n\t\tfor i := 0; i < tc.DaysOffset; i++ {\n\t\t\tcurrTime := time.Now().In(time.FixedZone(\"America/New_York\", -5*60*60))\n\t\t\t// add offset days to currTime so we can query for games in the future\n\t\t\tcurrTime = currTime.AddDate(0, 0, i)\n\t\t\tdateStr := currTime.Format(NBADateFormat)\n\t\t\tscheduleURLEndpoint := fmt.Sprintf(NBAScheduleURL, currentNBASeason, dateStr)\n\t\t\tenv.On(\"HTTPRequest\", scheduleURLEndpoint).Return([]byte(tc.JSONResponse), tc.Error)\n\t\t}\n\n\t\tnba := &Nba{}\n\t\tnba.Init(props, env)\n\n\t\tenabled := nba.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, nba.Template(), nba), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/nbgv.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n)\n\ntype Nbgv struct {\n\tBase\n\n\tVersionInfo\n}\n\ntype VersionInfo struct {\n\tVersion                      string `json:\"Version\"`\n\tAssemblyVersion              string `json:\"AssemblyVersion\"`\n\tAssemblyInformationalVersion string `json:\"AssemblyInformationalVersion\"`\n\tNuGetPackageVersion          string `json:\"NuGetPackageVersion\"`\n\tChocolateyPackageVersion     string `json:\"ChocolateyPackageVersion\"`\n\tNpmPackageVersion            string `json:\"NpmPackageVersion\"`\n\tSimpleVersion                string `json:\"SimpleVersion\"`\n\tVersionFileFound             bool   `json:\"VersionFileFound\"`\n}\n\nfunc (n *Nbgv) Template() string {\n\treturn \" {{ .Version }} \"\n}\n\nfunc (n *Nbgv) Enabled() bool {\n\tnbgv := \"nbgv\"\n\tif !n.env.HasCommand(nbgv) {\n\t\treturn false\n\t}\n\n\tresponse, err := n.env.RunCommand(nbgv, \"get-version\", \"--format=json\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tn.VersionInfo = VersionInfo{}\n\terr = json.Unmarshal([]byte(response), &n.VersionInfo)\n\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn n.VersionFileFound\n}\n"
  },
  {
    "path": "src/segments/nbgv_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestNbgv(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tExpectedString  string\n\t\tResponse        string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t\tHasNbgv         bool\n\t}{\n\t\t{Case: \"nbgv not installed\"},\n\t\t{Case: \"nbgv installed, no version file\", HasNbgv: true, Response: \"{ \\\"VersionFileFound\\\": false }\"},\n\t\t{Case: \"nbgv installed with version file\", ExpectedEnabled: true, HasNbgv: true, Response: \"{ \\\"VersionFileFound\\\": true }\"},\n\t\t{\n\t\t\tCase:            \"invalid template\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"invalid template text\",\n\t\t\tHasNbgv:         true,\n\t\t\tResponse:        \"{ \\\"VersionFileFound\\\": true }\",\n\t\t\tTemplate:        \"{{ err }}\",\n\t\t},\n\t\t{\n\t\t\tCase:    \"command error\",\n\t\t\tHasNbgv: true,\n\t\t\tError:   errors.New(\"oh noes\"),\n\t\t},\n\t\t{\n\t\t\tCase:     \"invalid json\",\n\t\t\tHasNbgv:  true,\n\t\t\tResponse: \"><<<>>>\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Version\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"bump\",\n\t\t\tHasNbgv:         true,\n\t\t\tResponse:        \"{ \\\"VersionFileFound\\\": true, \\\"Version\\\": \\\"bump\\\" }\",\n\t\t\tTemplate:        \"{{ .Version }}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"AssemblyVersion\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"bump\",\n\t\t\tHasNbgv:         true,\n\t\t\tResponse:        \"{ \\\"VersionFileFound\\\": true, \\\"AssemblyVersion\\\": \\\"bump\\\" }\",\n\t\t\tTemplate:        \"{{ .AssemblyVersion }}\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasCommand\", \"nbgv\").Return(tc.HasNbgv)\n\t\tenv.On(\"RunCommand\", \"nbgv\", []string{\"get-version\", \"--format=json\"}).Return(tc.Response, tc.Error)\n\n\t\tnbgv := &Nbgv{}\n\t\tnbgv.Init(options.Map{}, env)\n\n\t\tenabled := nbgv.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = nbgv.Template()\n\t\t}\n\t\tif enabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, nbgv), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/nightscout.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\thttp2 \"net/http\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// segment struct, makes templating easier\ntype Nightscout struct {\n\tBase\n\n\tTrendIcon string\n\tNightscoutData\n}\n\nconst (\n\t// Your complete Nightscout URL and APIKey like this\n\tURL     options.Option = \"url\"\n\tHeaders options.Option = \"headers\"\n\n\tDoubleUpIcon      options.Option = \"doubleup_icon\"\n\tSingleUpIcon      options.Option = \"singleup_icon\"\n\tFortyFiveUpIcon   options.Option = \"fortyfiveup_icon\"\n\tFlatIcon          options.Option = \"flat_icon\"\n\tFortyFiveDownIcon options.Option = \"fortyfivedown_icon\"\n\tSingleDownIcon    options.Option = \"singledown_icon\"\n\tDoubleDownIcon    options.Option = \"doubledown_icon\"\n)\n\n// NightscoutData struct contains the API data\ntype NightscoutData struct {\n\tDateString time.Time `json:\"dateString\"`\n\tSysTime    time.Time `json:\"sysTime\"`\n\tID         string    `json:\"_id\"`\n\tDirection  string    `json:\"direction\"`\n\tDevice     string    `json:\"device\"`\n\tType       string    `json:\"type\"`\n\tSgv        int       `json:\"sgv\"`\n\tDate       int64     `json:\"date\"`\n\tTrend      int       `json:\"trend\"`\n\tUtcOffset  int       `json:\"utcOffset\"`\n\tMills      int64     `json:\"mills\"`\n}\n\n// UnmarshalJSON handles both integer and floating-point JSON numbers for the date field.\n// Some Nightscout API providers (e.g. T1Pal) return the date as a float.\nfunc (n *NightscoutData) UnmarshalJSON(data []byte) error {\n\ttype Alias NightscoutData\n\taux := &struct {\n\t\t*Alias\n\t\tDate json.Number `json:\"date\"`\n\t}{\n\t\tAlias: (*Alias)(n),\n\t}\n\n\tif err := json.Unmarshal(data, aux); err != nil {\n\t\treturn err\n\t}\n\n\tif aux.Date == \"\" {\n\t\treturn nil\n\t}\n\n\tif i, err := aux.Date.Int64(); err == nil {\n\t\tn.Date = i\n\t\treturn nil\n\t}\n\n\tif f, err := aux.Date.Float64(); err == nil {\n\t\tn.Date = int64(f)\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"date field must be a valid number, got: %s\", aux.Date)\n}\n\nfunc (ns *Nightscout) Template() string {\n\treturn \" {{ .Sgv }} \"\n}\n\nfunc (ns *Nightscout) Enabled() bool {\n\tdata, err := ns.getResult()\n\tif err != nil {\n\t\treturn false\n\t}\n\tns.NightscoutData = *data\n\tns.TrendIcon = ns.getTrendIcon()\n\n\treturn true\n}\n\nfunc (ns *Nightscout) getTrendIcon() string {\n\tswitch ns.Direction {\n\tcase \"DoubleUp\":\n\t\treturn ns.options.String(DoubleUpIcon, \"↑↑\")\n\tcase \"SingleUp\":\n\t\treturn ns.options.String(SingleUpIcon, \"↑\")\n\tcase \"FortyFiveUp\":\n\t\treturn ns.options.String(FortyFiveUpIcon, \"↗\")\n\tcase \"Flat\":\n\t\treturn ns.options.String(FlatIcon, \"→\")\n\tcase \"FortyFiveDown\":\n\t\treturn ns.options.String(FortyFiveDownIcon, \"↘\")\n\tcase \"SingleDown\":\n\t\treturn ns.options.String(SingleDownIcon, \"↓\")\n\tcase \"DoubleDown\":\n\t\treturn ns.options.String(DoubleDownIcon, \"↓↓\")\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc (ns *Nightscout) getResult() (*NightscoutData, error) {\n\tparseSingleElement := func(data []byte) (*NightscoutData, error) {\n\t\tvar result []*NightscoutData\n\t\terr := json.Unmarshal(data, &result)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif len(result) == 0 {\n\t\t\treturn nil, errors.New(\"no elements in the array\")\n\t\t}\n\t\treturn result[0], nil\n\t}\n\n\turl := ns.options.Template(URL, \"\", ns)\n\thttpTimeout := ns.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\theaders := ns.options.KeyValueMap(Headers, map[string]string{})\n\tmodifiers := func(request *http2.Request) {\n\t\tfor key, value := range headers {\n\t\t\trequest.Header.Add(key, value)\n\t\t}\n\t}\n\n\tbody, err := ns.env.HTTPRequest(url, nil, httpTimeout, modifiers)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar arr []*NightscoutData\n\terr = json.Unmarshal(body, &arr)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tdata, err := parseSingleElement(body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn data, nil\n}\n"
  },
  {
    "path": "src/segments/nightscout_test.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tFAKEAPIURL = \"FAKE\"\n)\n\nfunc TestNSSegment(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tJSONResponse    string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tCacheTimeout    int\n\t\tExpectedEnabled bool\n\t\tCacheFoundFail  bool\n\t}{\n\t\t{\n\t\t\tCase: \"Flat 150\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":150,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"Flat\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 150→\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"DoubleDown 50\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":50,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"DoubleDown\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 50↓↓\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"DoubleUp 250\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":250,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"DoubleUp\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 250↑↑\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"SingleUp 130\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":130,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"SingleUp\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 130↑\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"FortyFiveUp 174\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":174,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"FortyFiveUp\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 174↗\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"FortyFiveDown 61\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":61,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"FortyFiveDown\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 61↘\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"DoubleDown 50\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":50,\"date\":1637707537000,\"dateString\":\"2021-11-23T22:45:37.000Z\",\"trend\":4,\"direction\":\"DoubleDown\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2021-11-23T22:45:37.000Z\",\"mills\":1637707537000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 50↓↓\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Float date value\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"_id\":\"619d6fa819696e8ded5b2206\",\"sgv\":124,\"date\":1770512410938.386,\"dateString\":\"2026-02-08T01:00:10.000Z\",\"trend\":4,\"direction\":\"Flat\",\"device\":\"share2\",\"type\":\"sgv\",\"utcOffset\":0,\"sysTime\":\"2026-02-08T01:00:10.000Z\",\"mills\":1770512410000}]`, //nolint:lll\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 124→\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Error in retrieving data\",\n\t\t\tJSONResponse:    \"nonsense\",\n\t\t\tError:           errors.New(\"Something went wrong\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty array\",\n\t\t\tJSONResponse:    \"[]\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase: \"Error parsing response\",\n\t\t\tJSONResponse: `\n\t\t\t4tffgt4e4567`,\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.TrendIcon}}\",\n\t\t\tExpectedString:  \"\\ue2a1 50↓↓\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase: \"Faulty template\",\n\t\t\tJSONResponse: `\n\t\t\t[{\"sgv\":50,\"direction\":\"DoubleDown\"}]`,\n\t\t\tTemplate:        \"\\ue2a1 {{.Sgv}}{{.Burp}}\",\n\t\t\tExpectedString:  template.IncorrectTemplate,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tprops := options.Map{\n\t\t\tURL:     \"FAKE\",\n\t\t\tHeaders: map[string]string{\"Fake-Header\": \"xxxxx\"},\n\t\t}\n\n\t\tenv.On(\"HTTPRequest\", FAKEAPIURL).Return([]byte(tc.JSONResponse), tc.Error)\n\n\t\tns := &Nightscout{}\n\t\tns.Init(props, env)\n\n\t\tenabled := ns.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = ns.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, ns), tc.Case)\n\t}\n}\n\nfunc TestNightscoutDataUnmarshalJSON(t *testing.T) {\n\tcases := []struct {\n\t\tCase         string\n\t\tJSONInput    string\n\t\tExpectedDate int64\n\t\tExpectError  bool\n\t}{\n\t\t{\n\t\t\tCase:         \"Integer date value\",\n\t\t\tJSONInput:    `{\"date\": 1637707537000}`,\n\t\t\tExpectedDate: 1637707537000,\n\t\t},\n\t\t{\n\t\t\tCase:         \"Floating-point date value\",\n\t\t\tJSONInput:    `{\"date\": 1637707537000.5}`,\n\t\t\tExpectedDate: 1637707537000,\n\t\t},\n\t\t{\n\t\t\tCase:         \"Floating-point date with larger decimal\",\n\t\t\tJSONInput:    `{\"date\": 1637707537123.789}`,\n\t\t\tExpectedDate: 1637707537123,\n\t\t},\n\t\t{\n\t\t\tCase:        \"Invalid date value\",\n\t\t\tJSONInput:   `{\"date\": \"not-a-number\"}`,\n\t\t\tExpectError: true,\n\t\t},\n\t\t{\n\t\t\tCase:      \"Missing date field\",\n\t\t\tJSONInput: `{\"sgv\": 150}`,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tvar data NightscoutData\n\t\terr := json.Unmarshal([]byte(tc.JSONInput), &data)\n\n\t\tif tc.ExpectError {\n\t\t\tassert.Error(t, err, tc.Case)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.NoError(t, err, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedDate, data.Date, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/nim.go",
    "content": "package segments\n\ntype Nim struct {\n\tLanguage\n}\n\nfunc (n *Nim) Template() string {\n\treturn languageTemplate\n}\n\nfunc (n *Nim) Enabled() bool {\n\tn.extensions = []string{\"*.nim\", \"*.nims\"}\n\n\tn.tooling = map[string]*cmd{\n\t\t\"nim\": {\n\t\t\texecutable: \"nim\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Nim Compiler Version (?P<version>(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+))`,\n\t\t},\n\t}\n\tn.defaultTooling = []string{\"nim\"}\n\treturn n.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/nim_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNim(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{\n\t\t\tCase:           \"Nim 2.2.0\",\n\t\t\tExpectedString: \"2.2.0\",\n\t\t\tVersion:        \"Nim Compiler Version 2.2.0 [MacOSX: arm64]\\nCompiled at 2024-11-30\\nCopyright (c) 2006-2024 by Andreas Rumpf\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Nim 1.6.12\",\n\t\t\tExpectedString: \"1.6.12\",\n\t\t\tVersion:        \"Nim Compiler Version 1.6.12 [Linux: amd64]\\nCompiled at 2023-06-15\\nCopyright (c) 2006-2023 by Andreas Rumpf\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Nim 2.0.0\",\n\t\t\tExpectedString: \"2.0.0\",\n\t\t\tVersion:        \"Nim Compiler Version 2.0.0 [Windows: amd64]\\nCompiled at 2023-12-25\\nCopyright (c) 2006-2023 by Andreas Rumpf\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"nim\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.nim\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tn := &Nim{}\n\t\tn.Init(props, env)\n\t\tassert.True(t, n.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, n.Template(), n), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/nixshell.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n\t\"strings\"\n)\n\nconst (\n\tNONE = \"none\"\n)\n\ntype NixShell struct {\n\tBase\n\n\tType string\n}\n\nfunc (n *NixShell) Template() string {\n\treturn \"via {{ .Type }}-shell\"\n}\n\nfunc (n *NixShell) DetectType() string {\n\tshellType := n.env.Getenv(\"IN_NIX_SHELL\")\n\n\tswitch shellType {\n\tcase \"pure\", \"impure\":\n\t\treturn shellType\n\tdefault:\n\t\tif n.InNewNixShell() {\n\t\t\treturn UNKNOWN\n\t\t}\n\n\t\treturn NONE\n\t}\n}\n\n// Hack to detect if we're in a `nix shell` (in contrast to a `nix-shell`).\n// A better way to do this will be enabled by https://github.com/NixOS/nix/issues/6677\n// so we check if the PATH contains a nix store.\nfunc (n *NixShell) InNewNixShell() bool {\n\tpaths := filepath.SplitList(n.env.Getenv(\"PATH\"))\n\n\tfor _, p := range paths {\n\t\tif strings.Contains(p, \"/nix/store\") {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (n *NixShell) Enabled() bool {\n\tn.Type = n.DetectType()\n\n\treturn n.Type != NONE\n}\n"
  },
  {
    "path": "src/segments/nixshell_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tnixPath     = \"/nix/store/zznw8fnzss1vaqfg5hmv3y79s3hkqczi-devshell-dir/bin\"\n\tdefaultPath = \"/users/xyz/testing\"\n\tfullNixPath = defaultPath + \":\" + nixPath\n)\n\nfunc TestNixShellSegment(t *testing.T) {\n\tcases := []struct {\n\t\tname           string\n\t\texpectedString string\n\t\tshellType      string\n\t\tenabled        bool\n\t}{\n\t\t{\n\t\t\tname:           \"Pure Nix Shell\",\n\t\t\texpectedString: \"via pure-shell\",\n\t\t\tshellType:      \"pure\",\n\t\t\tenabled:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"Impure Nix Shell\",\n\t\t\texpectedString: \"via impure-shell\",\n\t\t\tshellType:      \"impure\",\n\t\t\tenabled:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"Unknown Nix Shell\",\n\t\t\texpectedString: \"via unknown-shell\",\n\t\t\tshellType:      \"unknown\",\n\t\t\tenabled:        true,\n\t\t},\n\t\t{\n\t\t\tname:           \"No Nix Shell\",\n\t\t\texpectedString: \"\",\n\t\t\tshellType:      \"\",\n\t\t\tenabled:        false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tenv := new(mock.Environment)\n\t\t\tenv.On(\"Getenv\", \"IN_NIX_SHELL\").Return(tc.shellType)\n\n\t\t\tpath := defaultPath\n\t\t\tif tc.shellType != \"\" {\n\t\t\t\tpath = fullNixPath\n\t\t\t}\n\n\t\t\tenv.On(\"Getenv\", \"PATH\").Return(path)\n\n\t\t\tn := NixShell{}\n\t\t\tn.Init(options.Map{}, env)\n\n\t\t\tassert.Equal(t, tc.enabled, n.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.name))\n\n\t\t\tif tc.enabled {\n\t\t\t\tassert.Equal(t, tc.expectedString, renderTemplate(env, n.Template(), n), tc.name)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/segments/node.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Node struct {\n\tPackageManagerIcon string\n\tPackageManagerName string\n\n\tLanguage\n}\n\nconst (\n\t// PnpmIcon illustrates PNPM is used\n\tPnpmIcon options.Option = \"pnpm_icon\"\n\t// YarnIcon illustrates Yarn is used\n\tYarnIcon options.Option = \"yarn_icon\"\n\t// NPMIcon illustrates NPM is used\n\tNPMIcon options.Option = \"npm_icon\"\n\t// BunIcon illustrates Bun is used\n\tBunIcon options.Option = \"bun_icon\"\n\t// FetchPackageManager shows if Bun, NPM, PNPM, or Yarn is used\n\tFetchPackageManager options.Option = \"fetch_package_manager\"\n)\n\nfunc (n *Node) Template() string {\n\treturn \" {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \"\n}\n\nfunc (n *Node) Enabled() bool {\n\tn.extensions = []string{\"*.js\", \"*.ts\", \"package.json\", \".nvmrc\", \"pnpm-workspace.yaml\", \".pnpmfile.cjs\", \".vue\"}\n\tn.tooling = map[string]*cmd{\n\t\t\"node\": {\n\t\t\texecutable: \"node\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:v(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tn.defaultTooling = []string{\"node\"}\n\tn.versionURLTemplate = \"https://github.com/nodejs/node/blob/main/doc/changelogs/CHANGELOG_V{{ .Major }}.md#{{ .Full }}\"\n\tn.Language.matchesVersionFile = n.matchesVersionFile\n\tn.Language.loadContext = n.loadContext\n\n\treturn n.Language.Enabled()\n}\n\nfunc (n *Node) loadContext() {\n\tif !n.options.Bool(FetchPackageManager, false) {\n\t\treturn\n\t}\n\n\tpackageManagerDefinitions := []struct {\n\t\tfileName     string\n\t\tname         string\n\t\ticonProperty options.Option\n\t\tdefaultIcon  string\n\t}{\n\t\t{\n\t\t\tfileName:     \"pnpm-lock.yaml\",\n\t\t\tname:         \"pnpm\",\n\t\t\ticonProperty: PnpmIcon,\n\t\t\tdefaultIcon:  \"\\ue865\",\n\t\t},\n\t\t{\n\t\t\tfileName:     \"yarn.lock\",\n\t\t\tname:         \"yarn\",\n\t\t\ticonProperty: YarnIcon,\n\t\t\tdefaultIcon:  \"\\ue6a7\",\n\t\t},\n\t\t{\n\t\t\tfileName:     \"bun.lockb\",\n\t\t\tname:         \"bun\",\n\t\t\ticonProperty: BunIcon,\n\t\t\tdefaultIcon:  \"\\ue76f\",\n\t\t},\n\t\t{\n\t\t\tfileName:     \"bun.lock\",\n\t\t\tname:         \"bun\",\n\t\t\ticonProperty: BunIcon,\n\t\t\tdefaultIcon:  \"\\ue76f\",\n\t\t},\n\t\t{\n\t\t\tfileName:     \"package-lock.json\",\n\t\t\tname:         \"npm\",\n\t\t\ticonProperty: NPMIcon,\n\t\t\tdefaultIcon:  \"\\uE71E\",\n\t\t},\n\t\t{\n\t\t\tfileName:     \"package.json\",\n\t\t\tname:         \"npm\",\n\t\t\ticonProperty: NPMIcon,\n\t\t\tdefaultIcon:  \"\\uE71E\",\n\t\t},\n\t}\n\n\tfor _, pm := range packageManagerDefinitions {\n\t\tif n.env.HasFiles(pm.fileName) {\n\t\t\tn.PackageManagerName = pm.name\n\t\t\tn.PackageManagerIcon = n.options.String(pm.iconProperty, pm.defaultIcon)\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (n *Node) matchesVersionFile() (string, bool) {\n\tfileVersion := n.env.FileContent(\".nvmrc\")\n\tif fileVersion == \"\" {\n\t\treturn \"\", true\n\t}\n\n\tfileVersion = strings.TrimSpace(fileVersion)\n\n\tif strings.HasPrefix(fileVersion, \"lts/\") {\n\t\tfileVersion = strings.ToLower(fileVersion)\n\t\tcodeName := strings.TrimPrefix(fileVersion, \"lts/\")\n\t\tswitch codeName {\n\t\tcase \"argon\":\n\t\t\tfileVersion = \"4.9.1\"\n\t\tcase \"boron\":\n\t\t\tfileVersion = \"6.17.1\"\n\t\tcase \"carbon\":\n\t\t\tfileVersion = \"8.17.0\"\n\t\tcase \"dubnium\":\n\t\t\tfileVersion = \"10.24.1\"\n\t\tcase \"erbium\":\n\t\t\tfileVersion = \"12.22.12\"\n\t\tcase \"fermium\":\n\t\t\tfileVersion = \"14.21.3\"\n\t\tcase \"gallium\":\n\t\t\tfileVersion = \"16.20.2\"\n\t\tcase \"hydrogen\":\n\t\t\tfileVersion = \"18.20.8\"\n\t\tcase \"iron\":\n\t\t\tfileVersion = \"20.19.6\"\n\t\tcase \"jod\":\n\t\t\tfileVersion = \"22.21.1\"\n\t\tcase \"krypton\":\n\t\t\tfileVersion = \"24.12.0\"\n\t\t}\n\t}\n\n\tre := fmt.Sprintf(\n\t\t`(?im)^v?%s(\\.?%s)?(\\.?%s)?$`,\n\t\tn.Major,\n\t\tn.Minor,\n\t\tn.Patch,\n\t)\n\n\tversion := strings.TrimSpace(fileVersion)\n\tversion = strings.TrimPrefix(version, \"v\")\n\n\treturn version, regex.MatchString(re, fileVersion)\n}\n"
  },
  {
    "path": "src/segments/node_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestNodeMatchesVersionFile(t *testing.T) {\n\tnodeVersion := Version{\n\t\tFull:  \"22.21.1\",\n\t\tMajor: \"22\",\n\t\tMinor: \"21\",\n\t\tPatch: \"1\",\n\t}\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedVersion string\n\t\tRCVersion       string\n\t\tExpected        bool\n\t}{\n\t\t{Case: \"no file context\", Expected: true, RCVersion: \"\"},\n\t\t{Case: \"version match\", Expected: true, ExpectedVersion: \"22.21.1\", RCVersion: \"22.21.1\"},\n\t\t{Case: \"version match with newline\", Expected: true, ExpectedVersion: \"22.21.1\", RCVersion: \"22.21.1\\n\"},\n\t\t{Case: \"version mismatch\", Expected: false, ExpectedVersion: \"3.2.1\", RCVersion: \"3.2.1\"},\n\t\t{Case: \"version match in other format\", Expected: true, ExpectedVersion: \"22.21.1\", RCVersion: \"v22.21.1\"},\n\t\t{Case: \"version match without patch\", Expected: true, ExpectedVersion: \"22.21\", RCVersion: \"22.21\"},\n\t\t{Case: \"version match without patch in other format\", Expected: true, ExpectedVersion: \"22.21\", RCVersion: \"v22.21\"},\n\t\t{Case: \"version match without minor\", Expected: true, ExpectedVersion: \"22\", RCVersion: \"22\"},\n\t\t{Case: \"version match without minor in other format\", Expected: true, ExpectedVersion: \"22\", RCVersion: \"v22\"},\n\t\t{Case: \"lts match\", Expected: true, ExpectedVersion: \"22.21.1\", RCVersion: \"lts/jod\"},\n\t\t{Case: \"lts match upper case\", Expected: true, ExpectedVersion: \"22.21.1\", RCVersion: \"lts/Jod\"},\n\t\t{Case: \"lts mismatch\", Expected: false, ExpectedVersion: \"8.17.0\", RCVersion: \"lts/carbon\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"FileContent\", \".nvmrc\").Return(tc.RCVersion)\n\n\t\tnode := &Node{\n\t\t\tLanguage: Language{\n\t\t\t\tVersion: nodeVersion,\n\t\t\t},\n\t\t}\n\t\tnode.Init(options.Map{}, env)\n\n\t\tversion, match := node.matchesVersionFile()\n\t\tassert.Equal(t, tc.Expected, match, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedVersion, version, tc.Case)\n\t}\n}\n\nfunc TestNodeInContext(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\thasPNPM        bool\n\t\thasYarn        bool\n\t\thasNPM         bool\n\t\thasDefault     bool\n\t\thasBun         bool\n\t\tPkgMgrEnabled  bool\n\t}{\n\t\t{Case: \"no package manager file\", ExpectedString: \"\", PkgMgrEnabled: true},\n\t\t{Case: \"pnpm\", hasPNPM: true, ExpectedString: \"pnpm\", PkgMgrEnabled: true},\n\t\t{Case: \"yarn\", hasYarn: true, ExpectedString: \"yarn\", PkgMgrEnabled: true},\n\t\t{Case: \"npm\", hasNPM: true, ExpectedString: \"npm\", PkgMgrEnabled: true},\n\t\t{Case: \"default\", hasDefault: true, ExpectedString: \"npm\", PkgMgrEnabled: true},\n\t\t{Case: \"disabled by pnpm\", hasPNPM: true, ExpectedString: \"\", PkgMgrEnabled: false},\n\t\t{Case: \"disabled by yarn\", hasYarn: true, ExpectedString: \"\", PkgMgrEnabled: false},\n\t\t{Case: \"pnpm and npm\", hasPNPM: true, hasNPM: true, ExpectedString: \"pnpm\", PkgMgrEnabled: true},\n\t\t{Case: \"yarn and npm\", hasYarn: true, hasNPM: true, ExpectedString: \"yarn\", PkgMgrEnabled: true},\n\t\t{Case: \"pnpm, yarn, and npm\", hasPNPM: true, hasYarn: true, hasNPM: true, ExpectedString: \"pnpm\", PkgMgrEnabled: true},\n\t\t{Case: \"bun\", hasBun: true, ExpectedString: \"bun\", PkgMgrEnabled: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasFiles\", \"pnpm-lock.yaml\").Return(tc.hasPNPM)\n\t\tenv.On(\"HasFiles\", \"yarn.lock\").Return(tc.hasYarn)\n\t\tenv.On(\"HasFiles\", \"package-lock.json\").Return(tc.hasNPM)\n\t\tenv.On(\"HasFiles\", \"package.json\").Return(tc.hasDefault)\n\t\tenv.On(\"HasFiles\", \"bun.lockb\").Return(tc.hasBun)\n\t\tenv.On(\"HasFiles\", \"bun.lock\").Return(tc.hasBun)\n\n\t\tprops := options.Map{\n\t\t\tPnpmIcon:            \"pnpm\",\n\t\t\tYarnIcon:            \"yarn\",\n\t\t\tNPMIcon:             \"npm\",\n\t\t\tBunIcon:             \"bun\",\n\t\t\tFetchPackageManager: tc.PkgMgrEnabled,\n\t\t}\n\n\t\tnode := &Node{}\n\t\tnode.Init(props, env)\n\n\t\tnode.loadContext()\n\t\tassert.Equal(t, tc.ExpectedString, node.PackageManagerIcon, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/npm.go",
    "content": "package segments\n\ntype Npm struct {\n\tLanguage\n}\n\nfunc (n *Npm) Enabled() bool {\n\tn.extensions = []string{\"package.json\", \"package-lock.json\"}\n\tn.tooling = map[string]*cmd{\n\t\t\"npm\": {\n\t\t\texecutable: \"npm\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tn.defaultTooling = []string{\"npm\"}\n\tn.versionURLTemplate = \"https://github.com/npm/cli/releases/tag/v{{ .Full }}\"\n\n\treturn n.Language.Enabled()\n}\n\nfunc (n *Npm) Template() string {\n\treturn \" \\ue71e {{.Full}} \"\n}\n"
  },
  {
    "path": "src/segments/npm_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestNpm(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"1.0.0\", ExpectedString: \"\\ue71e 1.0.0\", Version: \"1.0.0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"npm\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"package.json\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tnpm := &Npm{}\n\t\tnpm.Init(props, env)\n\t\tassert.True(t, npm.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, npm.Template(), npm), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/nx.go",
    "content": "package segments\n\ntype Nx struct {\n\tLanguage\n}\n\nfunc (a *Nx) Template() string {\n\treturn languageTemplate\n}\n\nfunc (a *Nx) Enabled() bool {\n\ta.extensions = []string{\"workspace.json\", \"nx.json\"}\n\ta.tooling = map[string]*cmd{\n\t\t\"nx\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\tgetVersion: a.getVersion,\n\t\t},\n\t}\n\ta.defaultTooling = []string{\"nx\"}\n\ta.versionURLTemplate = \"https://github.com/nrwl/nx/releases/tag/{{.Full}}\"\n\n\treturn a.Language.Enabled()\n}\n\nfunc (a *Nx) getVersion() (string, error) {\n\treturn a.nodePackageVersion(\"nx\")\n}\n"
  },
  {
    "path": "src/segments/ocaml.go",
    "content": "package segments\n\ntype OCaml struct {\n\tLanguage\n}\n\nfunc (o *OCaml) Template() string {\n\treturn languageTemplate\n}\n\nfunc (o *OCaml) Enabled() bool {\n\to.extensions = []string{\"*.ml\", \"*.mli\", \"dune\", \"dune-project\", \"dune-workspace\"}\n\to.tooling = map[string]*cmd{\n\t\t\"ocaml\": {\n\t\t\texecutable: \"ocaml\",\n\t\t\targs:       []string{\"-version\"},\n\t\t\tregex:      `The OCaml toplevel, version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))(-(?P<prerelease>[a-z]+))?)`,\n\t\t},\n\t}\n\to.defaultTooling = []string{\"ocaml\"}\n\n\treturn o.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/ocaml_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestOCaml(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"OCaml 4.12.0\", ExpectedString: \"4.12.0\", Version: \"The OCaml toplevel, version 4.12.0\"},\n\t\t{Case: \"OCaml 4.11.0\", ExpectedString: \"4.11.0\", Version: \"The OCaml toplevel, version 4.11.0\"},\n\t\t{Case: \"OCaml 4.13.0\", ExpectedString: \"4.13.0\", Version: \"The OCaml toplevel, version 4.13.0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"ocaml\",\n\t\t\tversionParam:  \"-version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.ml\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\to := &OCaml{}\n\t\to.Init(props, env)\n\t\tassert.True(t, o.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, o.Template(), o), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/options/map.go",
    "content": "package options\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n)\n\nfunc init() {\n\tgob.Register([]any{})\n\tgob.Register(map[string]any{})\n\tgob.Register(map[any]any{})\n\tgob.Register([]string{})\n\tgob.Register(map[string]string{})\n\tgob.Register([]int{})\n\tgob.Register([]float64{})\n\tgob.Register([]bool{})\n\tgob.Register(int64(0))\n\tgob.Register(uint64(0))\n\tgob.Register(float32(0))\n\tgob.Register(Map{})\n\tgob.Register((*Option)(nil))\n\tgob.Register(map[Option]any{})\n}\n\ntype Provider interface {\n\tColor(option Option, defaultValue color.Ansi) color.Ansi\n\tBool(option Option, defaultValue bool) bool\n\tString(option Option, defaultValue string) string\n\tTemplate(option Option, defaultValue string, context any) string\n\tFloat64(option Option, defaultValue float64) float64\n\tInt(option Option, defaultValue int) int\n\tKeyValueMap(option Option, defaultValue map[string]string) map[string]string\n\tStringArray(option Option, defaultValue []string) []string\n\tAny(option Option, defaultValue any) any\n}\n\n// Option defines one property of a segment for context\ntype Option string\n\n// general options used across Segments\nconst (\n\t// Style indicates the style to use\n\tStyle Option = \"style\"\n\t// FetchVersion decides whether to fetch the version number or not\n\tFetchVersion Option = \"fetch_version\"\n\t// AlwaysEnabled decides whether or not to always display the info\n\tAlwaysEnabled Option = \"always_enabled\"\n\t// VersionURLTemplate is the template to use when building language segment hyperlink\n\tVersionURLTemplate Option = \"version_url_template\"\n\t// DisplayError decides whether to display when an error occurs or not\n\tDisplayError Option = \"display_error\"\n\t// DisplayDefault hides or shows the default\n\tDisplayDefault Option = \"display_default\"\n\t// AccessToken is the access token to use for an API\n\tAccessToken Option = \"access_token\"\n\t// RefreshToken is the refresh token to use for an API\n\tRefreshToken Option = \"refresh_token\"\n\t// HTTPTimeout timeout used when executing http request\n\tHTTPTimeout Option = \"http_timeout\"\n\t// DefaultHTTPTimeout default timeout used when executing http request\n\tDefaultHTTPTimeout = 20\n\t// Files to trigger the segment on\n\tFiles Option = \"files\"\n\t// Duration of the cache\n\tCacheDuration Option = \"cache_duration\"\n)\n\ntype Map map[Option]any\n\nfunc (m Map) String(option Option, defaultValue string) string {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\tvalue := fmt.Sprint(val)\n\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, value))\n\treturn value\n}\n\n// Template resolves the option value as a template and returns the resolved string.\n// This allows using template syntax like {{ .Env.MY_API_KEY }} in configuration values.\n// If template rendering fails, it returns the original string value.\nfunc (m Map) Template(option Option, defaultValue string, context any) string {\n\tvalue := m.String(option, defaultValue)\n\tif value == \"\" {\n\t\treturn value\n\t}\n\n\tresolved, err := template.Render(value, context)\n\tif err != nil {\n\t\tlog.Debug(fmt.Sprintf(\"%s: template error, using raw value: %s\", option, err))\n\t\treturn value\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"%s (template resolved): %s\", option, resolved))\n\treturn resolved\n}\n\nfunc (m Map) Color(option Option, defaultValue color.Ansi) color.Ansi {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\tcolorString := color.Ansi(fmt.Sprint(val))\n\tif color.IsAnsiColorName(colorString) {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, colorString))\n\t\treturn colorString\n\t}\n\n\tvalues := regex.FindNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString.String())\n\tif values != nil && values[\"color\"] != \"\" {\n\t\tvalue := color.Ansi(values[\"color\"])\n\t\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, value))\n\t\treturn value\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"%s: %s\", option, defaultValue))\n\treturn defaultValue\n}\n\nfunc (m Map) Bool(option Option, defaultValue bool) bool {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %t\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\tboolValue, ok := val.(bool)\n\tif !ok {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %t\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\tlog.Debug(fmt.Sprintf(\"%s: %t\", option, boolValue))\n\treturn boolValue\n}\n\nfunc (m Map) Float64(option Option, defaultValue float64) float64 {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\t// Direct type conversions for common numeric types\n\tswitch v := val.(type) {\n\tcase float64:\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, v))\n\t\treturn v\n\tcase int:\n\t\tvalue := float64(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, value))\n\t\treturn value\n\tcase int64:\n\t\tvalue := float64(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, value))\n\t\treturn value\n\tcase uint64:\n\t\tvalue := float64(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, value))\n\t\treturn value\n\tdefault:\n\t\tlog.Debug(fmt.Sprintf(\"%s: %f\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n}\n\nfunc (m Map) Int(option Option, defaultValue int) int {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\t// Direct type conversions for common numeric types\n\tswitch v := val.(type) {\n\tcase int:\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, v))\n\t\treturn v\n\tcase int64:\n\t\tvalue := int(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, value))\n\t\treturn value\n\tcase uint64:\n\t\tvalue := int(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, value))\n\t\treturn value\n\tcase float64:\n\t\tvalue := int(v)\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, value))\n\t\treturn value\n\tdefault:\n\t\tlog.Debug(fmt.Sprintf(\"%s: %d\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n}\n\nfunc (m Map) KeyValueMap(option Option, defaultValue map[string]string) map[string]string {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\tkeyValues := parseKeyValueArray(val)\n\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, keyValues))\n\treturn keyValues\n}\n\nfunc (m Map) StringArray(option Option, defaultValue []string) []string {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\tkeyValues := ParseStringArray(val)\n\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, keyValues))\n\treturn keyValues\n}\n\nfunc (m Map) Any(option Option, defaultValue any) any {\n\tval, found := m[option]\n\tif !found {\n\t\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, defaultValue))\n\t\treturn defaultValue\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"%s: %v\", option, val))\n\treturn val\n}\n\nfunc ParseStringArray(param any) []string {\n\treturn generics.ParseStringSlice(param)\n}\n\nfunc parseKeyValueArray(param any) map[string]string {\n\tswitch v := param.(type) {\n\tdefault:\n\t\treturn map[string]string{}\n\tcase map[any]any:\n\t\tkeyValueArray := make(map[string]string)\n\t\tfor key, value := range v {\n\t\t\tval := value.(string)\n\t\t\tkeyString := fmt.Sprintf(\"%v\", key)\n\t\t\tkeyValueArray[keyString] = val\n\t\t}\n\t\treturn keyValueArray\n\tcase map[string]any:\n\t\tkeyValueArray := make(map[string]string)\n\t\tfor key, value := range v {\n\t\t\tval := value.(string)\n\t\t\tkeyValueArray[key] = val\n\t\t}\n\t\treturn keyValueArray\n\tcase []any:\n\t\tkeyValueArray := make(map[string]string)\n\t\tfor _, s := range v {\n\t\t\tl := ParseStringArray(s)\n\t\t\tif len(l) == 2 {\n\t\t\t\tkey := l[0]\n\t\t\t\tval := l[1]\n\t\t\t\tkeyValueArray[key] = val\n\t\t\t}\n\t\t}\n\t\treturn keyValueArray\n\tcase Map:\n\t\tkeyValueArray := make(map[string]string)\n\t\tfor key, value := range v {\n\t\t\tval := value.(string)\n\t\t\tkeyString := fmt.Sprintf(\"%v\", key)\n\t\t\tkeyValueArray[keyString] = val\n\t\t}\n\t\treturn keyValueArray\n\tcase map[string]string:\n\t\treturn v\n\t}\n}\n\n// Generic functions\n\ntype Value interface {\n\tstring | int | []string | float64 | bool\n}\n\nfunc OneOf[T Value](options Provider, defaultValue T, props ...Option) T {\n\tfor _, prop := range props {\n\t\t// get value on a generic get, then see if we can cast to T?\n\t\tval := options.Any(prop, nil)\n\t\tif val == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif v, ok := val.(T); ok {\n\t\t\treturn v\n\t\t}\n\t}\n\n\treturn defaultValue\n}\n"
  },
  {
    "path": "src/segments/options/map_test.go",
    "content": "package options\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\texpected      = \"expected\"\n\texpectedColor = color.Ansi(\"#768954\")\n\n\tFoo Option = \"color\"\n)\n\nfunc TestGetString(t *testing.T) {\n\tvar options = Map{Foo: expected}\n\tvalue := options.String(Foo, \"err\")\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestGetStringNoEntry(t *testing.T) {\n\tvar options = Map{}\n\tvalue := options.String(Foo, expected)\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestGetStringNoTextEntry(t *testing.T) {\n\tvar options = Map{Foo: true}\n\tvalue := options.String(Foo, expected)\n\tassert.Equal(t, \"true\", value)\n}\n\nfunc TestGetHexColor(t *testing.T) {\n\texpected := expectedColor\n\tvar options = Map{Foo: expected}\n\tvalue := options.Color(Foo, \"#789123\")\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestGetColor(t *testing.T) {\n\texpected := color.Ansi(\"yellow\")\n\tvar options = Map{Foo: expected}\n\tvalue := options.Color(Foo, \"#789123\")\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestDefaultColorWithInvalidColorCode(t *testing.T) {\n\texpected := expectedColor\n\tvar options = Map{Foo: \"invalid\"}\n\tvalue := options.Color(Foo, expected)\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestDefaultColorWithUnavailableProperty(t *testing.T) {\n\texpected := expectedColor\n\tvar options = Map{}\n\tvalue := options.Color(Foo, expected)\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestGetPaletteColor(t *testing.T) {\n\texpected := color.Ansi(\"p:red\")\n\tvar options = Map{Foo: expected}\n\tvalue := options.Color(Foo, \"white\")\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestGetBool(t *testing.T) {\n\texpected := true\n\tvar options = Map{Foo: expected}\n\tvalue := options.Bool(Foo, false)\n\tassert.True(t, value)\n}\n\nfunc TestGetBoolPropertyNotInMap(t *testing.T) {\n\tvar options = Map{}\n\tvalue := options.Bool(Foo, false)\n\tassert.False(t, value)\n}\n\nfunc TestGetBoolInvalidProperty(t *testing.T) {\n\tvar options = Map{Foo: \"borked\"}\n\tvalue := options.Bool(Foo, false)\n\tassert.False(t, value)\n}\n\nfunc TestGetFloat64(t *testing.T) {\n\tcases := []struct {\n\t\tInput    any\n\t\tCase     string\n\t\tExpected float64\n\t}{\n\t\t{Case: \"int\", Expected: 1337, Input: 1337},\n\t\t{Case: \"float64\", Expected: 1337, Input: float64(1337)},\n\t\t{Case: \"uint64\", Expected: 1337, Input: uint64(1337)},\n\t\t{Case: \"int64\", Expected: 1337, Input: int64(1337)},\n\t\t{Case: \"string\", Expected: 9001, Input: \"invalid\"},\n\t\t{Case: \"bool\", Expected: 9001, Input: true},\n\t}\n\tfor _, tc := range cases {\n\t\toptions := Map{Foo: tc.Input}\n\t\tvalue := options.Float64(Foo, 9001)\n\t\tassert.Equal(t, tc.Expected, value, tc.Case)\n\t}\n}\n\nfunc TestGetFloat64PropertyNotInMap(t *testing.T) {\n\texpected := float64(1337)\n\tvar options = Map{}\n\tvalue := options.Float64(Foo, expected)\n\tassert.Equal(t, expected, value)\n}\n\nfunc TestOneOf(t *testing.T) {\n\tcases := []struct {\n\t\tExpected     any\n\t\tMap          Map\n\t\tCase         string\n\t\tDefaultValue string\n\t\tOptions      []Option\n\t}{\n\t\t{\n\t\t\tCase:     \"one element\",\n\t\t\tExpected: \"1337\",\n\t\t\tOptions:  []Option{Foo},\n\t\t\tMap: Map{\n\t\t\t\tFoo: \"1337\",\n\t\t\t},\n\t\t\tDefaultValue: \"2000\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"two elements\",\n\t\t\tExpected: \"1337\",\n\t\t\tOptions:  []Option{Foo},\n\t\t\tMap: Map{\n\t\t\t\tFoo:   \"1337\",\n\t\t\t\t\"Bar\": \"9001\",\n\t\t\t},\n\t\t\tDefaultValue: \"2000\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"no match\",\n\t\t\tExpected: \"2000\",\n\t\t\tOptions:  []Option{\"Moo\"},\n\t\t\tMap: Map{\n\t\t\t\tFoo:   \"1337\",\n\t\t\t\t\"Bar\": \"9001\",\n\t\t\t},\n\t\t\tDefaultValue: \"2000\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"incorrect type\",\n\t\t\tExpected: \"2000\",\n\t\t\tOptions:  []Option{Foo},\n\t\t\tMap: Map{\n\t\t\t\tFoo:   1337,\n\t\t\t\t\"Bar\": \"9001\",\n\t\t\t},\n\t\t\tDefaultValue: \"2000\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tvalue := OneOf(tc.Map, tc.DefaultValue, tc.Options...)\n\t\tassert.Equal(t, tc.Expected, value, tc.Case)\n\t}\n}\n\nfunc TestTemplate(t *testing.T) {\n\t// Need to initialize template package for testing\n\tenv := &mock.Environment{}\n\tenv.On(\"Getenv\", \"MY_API_KEY\").Return(\"secret-key-123\")\n\tenv.On(\"Getenv\", \"MY_USER\").Return(\"testuser\")\n\tenv.On(\"Getenv\", \"SHLVL\").Return(\"1\")\n\tenv.On(\"Shell\").Return(\"bash\")\n\tenv.On(\"Flags\").Return(&runtime.Flags{\n\t\tIsPrimary:    true,\n\t\tShellVersion: \"1.0.0\",\n\t\tPromptCount:  1,\n\t\tJobCount:     0,\n\t\tPSWD:         \"/home/test\",\n\t\tAbsolutePWD:  \"/home/test\",\n\t})\n\tenv.On(\"Root\").Return(false)\n\tenv.On(\"StatusCodes\").Return(0, \"0\")\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"Pwd\").Return(\"/home/test\")\n\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\tenv.On(\"Platform\").Return(\"ubuntu\")\n\tenv.On(\"User\").Return(\"testuser\")\n\tenv.On(\"Host\").Return(\"testhost\", nil)\n\n\t// Initialize template package\n\ttemplate.Init(env, nil, nil)\n\n\tcases := []struct {\n\t\tCase         string\n\t\tOptions      Map\n\t\tOption       Option\n\t\tDefaultValue string\n\t\tContext      any\n\t\tExpected     string\n\t}{\n\t\t{\n\t\t\tCase:         \"plain string no template\",\n\t\t\tOptions:      Map{\"key\": \"plain-value\"},\n\t\t\tOption:       \"key\",\n\t\t\tDefaultValue: \"\",\n\t\t\tContext:      nil,\n\t\t\tExpected:     \"plain-value\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"template with env var\",\n\t\t\tOptions:      Map{\"key\": \"{{ .Env.MY_API_KEY }}\"},\n\t\t\tOption:       \"key\",\n\t\t\tDefaultValue: \"\",\n\t\t\tContext:      nil,\n\t\t\tExpected:     \"secret-key-123\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"template with multiple env vars\",\n\t\t\tOptions:      Map{\"key\": \"{{ .Env.MY_USER }}/{{ .Env.MY_API_KEY }}\"},\n\t\t\tOption:       \"key\",\n\t\t\tDefaultValue: \"\",\n\t\t\tContext:      nil,\n\t\t\tExpected:     \"testuser/secret-key-123\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"empty value returns default\",\n\t\t\tOptions:      Map{},\n\t\t\tOption:       \"key\",\n\t\t\tDefaultValue: \"default-value\",\n\t\t\tContext:      nil,\n\t\t\tExpected:     \"default-value\",\n\t\t},\n\t\t{\n\t\t\tCase:         \"invalid template returns raw value\",\n\t\t\tOptions:      Map{\"key\": \"{{ .Invalid }}\"},\n\t\t\tOption:       \"key\",\n\t\t\tDefaultValue: \"\",\n\t\t\tContext:      nil,\n\t\t\tExpected:     \"{{ .Invalid }}\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tvalue := tc.Options.Template(tc.Option, tc.DefaultValue, tc.Context)\n\t\tassert.Equal(t, tc.Expected, value, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/os.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Os struct {\n\tBase\n\n\tIcon string\n}\n\nconst (\n\t// MacOS the string/icon to use for MacOS\n\tMacOS options.Option = \"macos\"\n\t// Linux the string/icon to use for linux\n\tLinux options.Option = \"linux\"\n\t// Windows the string/icon to use for windows\n\tWindows options.Option = \"windows\"\n\t// Android the string/icon to use for android\n\tAndroid options.Option = \"android\"\n\t// DisplayDistroName display the distro name or not\n\tDisplayDistroName options.Option = \"display_distro_name\"\n)\n\nfunc (oi *Os) Template() string {\n\treturn \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \"\n}\n\nfunc (oi *Os) Enabled() bool {\n\tgoos := oi.env.GOOS()\n\tswitch goos {\n\tcase runtime.WINDOWS:\n\t\toi.Icon = oi.options.String(Windows, \"\\uE62A\")\n\tcase runtime.DARWIN:\n\t\toi.Icon = oi.options.String(MacOS, \"\\uF179\")\n\tcase runtime.LINUX, runtime.FREEBSD:\n\t\tpf := oi.env.Platform()\n\t\tdisplayDistroName := oi.options.Bool(DisplayDistroName, false)\n\t\tif displayDistroName {\n\t\t\toi.Icon = oi.options.String(options.Option(pf), pf)\n\t\t\tbreak\n\t\t}\n\t\toi.Icon = oi.getDistroIcon(pf)\n\tcase runtime.ANDROID:\n\t\toi.Icon = oi.options.String(Android, \"\\ue70e\")\n\tdefault:\n\t\toi.Icon = goos\n\t}\n\treturn true\n}\n\nfunc (oi *Os) getDistroIcon(distro string) string {\n\ticonMap := map[string]string{\n\t\t\"alma\":                \"\\uf31d\",\n\t\t\"almalinux\":           \"\\uf31d\",\n\t\t\"almalinux9\":          \"\\uf31d\",\n\t\t\"alpine\":              \"\\uf300\",\n\t\t\"android\":             \"\\ue70e\",\n\t\t\"aosc\":                \"\\uf301\",\n\t\t\"arch\":                \"\\uf303\",\n\t\t\"centos\":              \"\\uf304\",\n\t\t\"coreos\":              \"\\uf305\",\n\t\t\"debian\":              \"\\uf306\",\n\t\t\"deepin\":              \"\\uf321\",\n\t\t\"devuan\":              \"\\uf307\",\n\t\t\"elementary\":          \"\\uf309\",\n\t\t\"endeavouros\":         \"\\uf322\",\n\t\t\"fedora\":              \"\\uf30a\",\n\t\t\"freebsd\":             \"\\U000f08e0\",\n\t\t\"gentoo\":              \"\\uf30d\",\n\t\t\"kali\":                \"\\uf327\",\n\t\t\"mageia\":              \"\\uf310\",\n\t\t\"manjaro\":             \"\\uf312\",\n\t\t\"mint\":                \"\\U000f08ed\",\n\t\t\"neon\":                \"\\uf331\",\n\t\t\"nixos\":               \"\\uf313\",\n\t\t\"opensuse\":            \"\\uf314\",\n\t\t\"opensuse-tumbleweed\": \"\\uf314\",\n\t\t\"raspbian\":            \"\\uf315\",\n\t\t\"redhat\":              \"\\uf316\",\n\t\t\"rocky\":               \"\\uf32b\",\n\t\t\"sabayon\":             \"\\uf317\",\n\t\t\"slackware\":           \"\\uf319\",\n\t\t\"ubuntu\":              \"\\uf31b\",\n\t\t\"void\":                \"\\uf32e\",\n\t\t\"zorin\":               \"\\uf32f\",\n\t}\n\n\tif icon, ok := iconMap[distro]; ok {\n\t\treturn oi.options.String(options.Option(distro), icon)\n\t}\n\n\ticon := oi.options.String(options.Option(distro), \"\")\n\tif len(icon) > 0 {\n\t\treturn icon\n\t}\n\n\treturn oi.options.String(Linux, \"\\uF17C\")\n}\n"
  },
  {
    "path": "src/segments/os_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestOSInfo(t *testing.T) {\n\tcases := []struct {\n\t\tCase              string\n\t\tExpectedString    string\n\t\tGOOS              string\n\t\tPlatform          string\n\t\tIcon              string\n\t\tIsWSL             bool\n\t\tDisplayDistroName bool\n\t}{\n\t\t{\n\t\t\tCase:           \"WSL debian - icon\",\n\t\t\tExpectedString: \"WSL at \\uf306\",\n\t\t\tGOOS:           \"linux\",\n\t\t\tIsWSL:          true,\n\t\t\tPlatform:       \"debian\",\n\t\t},\n\t\t{\n\t\t\tCase:              \"WSL debian - name\",\n\t\t\tExpectedString:    \"WSL at debian\",\n\t\t\tGOOS:              \"linux\",\n\t\t\tIsWSL:             true,\n\t\t\tPlatform:          \"debian\",\n\t\t\tDisplayDistroName: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"plain linux - icon\",\n\t\t\tExpectedString: \"\\uf306\",\n\t\t\tGOOS:           \"linux\",\n\t\t\tPlatform:       \"debian\",\n\t\t},\n\t\t{\n\t\t\tCase:              \"plain linux - name\",\n\t\t\tExpectedString:    \"debian\",\n\t\t\tGOOS:              \"linux\",\n\t\t\tPlatform:          \"debian\",\n\t\t\tDisplayDistroName: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"windows\",\n\t\t\tExpectedString: \"windows\",\n\t\t\tGOOS:           \"windows\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"darwin\",\n\t\t\tExpectedString: \"darwin\",\n\t\t\tGOOS:           \"darwin\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"unknown\",\n\t\t\tExpectedString: \"unknown\",\n\t\t\tGOOS:           \"unknown\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"crazy distro, specific icon\",\n\t\t\tExpectedString: \"crazy distro\",\n\t\t\tGOOS:           \"linux\",\n\t\t\tPlatform:       \"crazy\",\n\t\t\tIcon:           \"crazy distro\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"crazy distro, not mapped\",\n\t\t\tExpectedString: \"\\uf17c\",\n\t\t\tGOOS:           \"linux\",\n\t\t\tPlatform:       \"crazy\",\n\t\t},\n\t\t{\n\t\t\tCase:              \"show distro name, mapped\",\n\t\t\tExpectedString:    \"<3\",\n\t\t\tDisplayDistroName: true,\n\t\t\tGOOS:              \"linux\",\n\t\t\tIcon:              \"<3\",\n\t\t\tPlatform:          \"love\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\tenv.On(\"Platform\").Return(tc.Platform)\n\n\t\tprops := options.Map{\n\t\t\tDisplayDistroName: tc.DisplayDistroName,\n\t\t\tWindows:           \"windows\",\n\t\t\tMacOS:             \"darwin\",\n\t\t}\n\n\t\tif len(tc.Icon) != 0 {\n\t\t\tprops[options.Option(tc.Platform)] = tc.Icon\n\t\t}\n\n\t\tosInfo := &Os{}\n\t\tosInfo.Init(props, env)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tWSL: tc.IsWSL,\n\t\t\t},\n\t\t}\n\n\t\t_ = osInfo.Enabled()\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, osInfo.Template(), osInfo), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/owm.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net/url\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Owm struct {\n\tBase\n\n\tWeather     string\n\tURL         string\n\tunits       string\n\tUnitIcon    string\n\tTemperature int\n}\n\nconst (\n\t// APIKey openweathermap api key\n\tAPIKey options.Option = \"api_key\"\n\t// Location openweathermap location\n\tLocation options.Option = \"location\"\n\t// Units openweathermap units\n\tUnits options.Option = \"units\"\n\t// CacheKeyResponse key used when caching the response\n\tCacheKeyResponse string = \"owm_response\"\n\t// CacheKeyURL key used when caching the url responsible for the response\n\tCacheKeyURL string = \"owm_url\"\n)\n\ntype weather struct {\n\tShortDescription string `json:\"main\"`\n\tDescription      string `json:\"description\"`\n\tTypeID           string `json:\"icon\"`\n}\ntype temperature struct {\n\tValue float64 `json:\"temp\"`\n}\n\ntype owmDataResponse struct {\n\tData        []weather `json:\"weather\"`\n\ttemperature `json:\"main\"`\n}\n\nfunc (d *Owm) Enabled() bool {\n\terr := d.setStatus()\n\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (d *Owm) Template() string {\n\treturn \" {{ .Weather }} ({{ .Temperature }}{{ .UnitIcon }}) \"\n}\n\nfunc (d *Owm) getResult() (*owmDataResponse, error) {\n\tresponse := new(owmDataResponse)\n\n\tapikey := d.options.Template(APIKey, \"\", d)\n\tif apikey == \"\" {\n\t\treturn nil, errors.New(\"no api key found\")\n\t}\n\n\tlocation := d.options.Template(Location, \"\", d)\n\tif location == \"\" {\n\t\treturn nil, errors.New(\"no location found\")\n\t}\n\n\tlocation = url.QueryEscape(location)\n\n\tunits := d.options.String(Units, \"standard\")\n\thttpTimeout := d.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\td.URL = fmt.Sprintf(\"https://api.openweathermap.org/data/2.5/weather?q=%s&units=%s&appid=%s\", location, units, apikey)\n\n\tbody, err := d.env.HTTPRequest(d.URL, nil, httpTimeout)\n\tif err != nil {\n\t\treturn new(owmDataResponse), err\n\t}\n\n\terr = json.Unmarshal(body, &response)\n\tif err != nil {\n\t\treturn new(owmDataResponse), err\n\t}\n\n\treturn response, nil\n}\n\nfunc (d *Owm) setStatus() error {\n\tunits := d.options.String(Units, \"standard\")\n\n\tq, err := d.getResult()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif len(q.Data) == 0 {\n\t\treturn errors.New(\"no data found\")\n\t}\n\n\tid := q.Data[0].TypeID\n\n\td.Temperature = int(math.Round(q.Value))\n\ticon := \"\"\n\tswitch id {\n\tcase \"01n\":\n\t\ticon = \"\\ue32b\"\n\tcase \"01d\":\n\t\ticon = \"\\ue30d\"\n\tcase \"02n\":\n\t\ticon = \"\\ue37e\"\n\tcase \"02d\":\n\t\ticon = \"\\ue302\"\n\tcase \"03n\":\n\t\tfallthrough\n\tcase \"03d\":\n\t\ticon = \"\\ue33d\"\n\tcase \"04n\":\n\t\tfallthrough\n\tcase \"04d\":\n\t\ticon = \"\\ue312\"\n\tcase \"09n\":\n\t\tfallthrough\n\tcase \"09d\":\n\t\ticon = \"\\ue319\"\n\tcase \"10n\":\n\t\ticon = \"\\ue325\"\n\tcase \"10d\":\n\t\ticon = \"\\ue308\"\n\tcase \"11n\":\n\t\ticon = \"\\ue32a\"\n\tcase \"11d\":\n\t\ticon = \"\\ue30f\"\n\tcase \"13n\":\n\t\tfallthrough\n\tcase \"13d\":\n\t\ticon = \"\\ue31a\"\n\tcase \"50n\":\n\t\tfallthrough\n\tcase \"50d\":\n\t\ticon = \"\\ue313\"\n\t}\n\td.Weather = icon\n\td.units = units\n\td.UnitIcon = \"\\ue33e\"\n\tswitch d.units {\n\tcase \"imperial\":\n\t\td.UnitIcon = \"°F\" // \\ue341\"\n\tcase \"metric\":\n\t\td.UnitIcon = \"°C\" // \\ue339\"\n\tcase \"\":\n\t\tfallthrough\n\tcase \"standard\":\n\t\td.UnitIcon = \"°K\" // <b>K</b>\"\n\t}\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/owm_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tOWMWEATHERAPIURL = \"https://api.openweathermap.org/data/2.5/weather?q=%s&units=metric&appid=key\"\n)\n\nfunc TestOWMSegmentSingle(t *testing.T) {\n\tcases := []struct {\n\t\tError               error\n\t\tCase                string\n\t\tLocation            string\n\t\tWeatherJSONResponse string\n\t\tExpectedString      string\n\t\tTemplate            string\n\t\tExpectedEnabled     bool\n\t}{\n\t\t{\n\t\t\tCase:                \"Sunny Display\",\n\t\t\tLocation:            \"AMSTERDAM,NL\",\n\t\t\tWeatherJSONResponse: `{\"weather\":[{\"icon\":\"01d\"}],\"main\":{\"temp\":20}}`,\n\t\t\tExpectedString:      \"\\ue30d (20°C)\",\n\t\t\tExpectedEnabled:     true,\n\t\t},\n\t\t{\n\t\t\tCase:                \"Sunny Display\",\n\t\t\tLocation:            \"AMSTERDAM,NL\",\n\t\t\tWeatherJSONResponse: `{\"weather\":[{\"icon\":\"01d\"}],\"main\":{\"temp\":20}}`,\n\t\t\tExpectedString:      \"\\ue30d (20°C)\",\n\t\t\tExpectedEnabled:     true,\n\t\t\tTemplate:            \"{{.Weather}} ({{.Temperature}}{{.UnitIcon}})\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"Sunny Display\",\n\t\t\tLocation:            \"AMSTERDAM,NL\",\n\t\t\tWeatherJSONResponse: `{\"weather\":[{\"icon\":\"01d\"}],\"main\":{\"temp\":20}}`,\n\t\t\tExpectedString:      \"\\ue30d\",\n\t\t\tExpectedEnabled:     true,\n\t\t\tTemplate:            \"{{.Weather}} \",\n\t\t},\n\t\t{\n\t\t\tCase:                \"Config Skip Geocoding Check With Location\",\n\t\t\tLocation:            \"AMSTERDAM,NL\",\n\t\t\tWeatherJSONResponse: `{\"weather\":[{\"icon\":\"01d\"}],\"main\":{\"temp\":20}}`,\n\t\t\tExpectedString:      \"\\ue30d (20°C)\",\n\t\t\tExpectedEnabled:     true,\n\t\t},\n\t\t{\n\t\t\tCase:                \"Config Skip Geocoding Check Without Location\",\n\t\t\tWeatherJSONResponse: `{\"weather\":[{\"icon\":\"01d\"}],\"main\":{\"temp\":20}}`,\n\t\t\tExpectedEnabled:     false,\n\t\t},\n\t\t{\n\t\t\tCase:                \"Error in retrieving data\",\n\t\t\tLocation:            \"AMSTERDAM,NL\",\n\t\t\tWeatherJSONResponse: \"nonsense\",\n\t\t\tError:               errors.New(\"Something went wrong\"),\n\t\t\tExpectedEnabled:     false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tprops := options.Map{\n\t\t\tAPIKey:   \"key\",\n\t\t\tLocation: tc.Location,\n\t\t\tUnits:    \"metric\",\n\t\t}\n\n\t\tlocation := url.QueryEscape(tc.Location)\n\t\ttestURL := fmt.Sprintf(OWMWEATHERAPIURL, location)\n\t\tenv.On(\"HTTPRequest\", testURL).Return([]byte(tc.WeatherJSONResponse), tc.Error)\n\n\t\to := &Owm{}\n\t\to.Init(props, env)\n\n\t\tenabled := o.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = o.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, o), tc.Case)\n\t}\n}\n\nfunc TestOWMSegmentIcons(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tIconID             string\n\t\tExpectedIconString string\n\t}{\n\t\t{\n\t\t\tCase:               \"Sunny Display day\",\n\t\t\tIconID:             \"01d\",\n\t\t\tExpectedIconString: \"\\ue30d\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Light clouds Display day\",\n\t\t\tIconID:             \"02d\",\n\t\t\tExpectedIconString: \"\\ue302\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Cloudy Display day\",\n\t\t\tIconID:             \"03d\",\n\t\t\tExpectedIconString: \"\\ue33d\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Broken Clouds Display day\",\n\t\t\tIconID:             \"04d\",\n\t\t\tExpectedIconString: \"\\ue312\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Shower Rain Display day\",\n\t\t\tIconID:             \"09d\",\n\t\t\tExpectedIconString: \"\\ue319\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Rain Display day\",\n\t\t\tIconID:             \"10d\",\n\t\t\tExpectedIconString: \"\\ue308\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Thunderstorm Display day\",\n\t\t\tIconID:             \"11d\",\n\t\t\tExpectedIconString: \"\\ue30f\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Snow Display day\",\n\t\t\tIconID:             \"13d\",\n\t\t\tExpectedIconString: \"\\ue31a\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Fog Display day\",\n\t\t\tIconID:             \"50d\",\n\t\t\tExpectedIconString: \"\\ue313\",\n\t\t},\n\n\t\t{\n\t\t\tCase:               \"Sunny Display night\",\n\t\t\tIconID:             \"01n\",\n\t\t\tExpectedIconString: \"\\ue32b\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Light clouds Display night\",\n\t\t\tIconID:             \"02n\",\n\t\t\tExpectedIconString: \"\\ue37e\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Cloudy Display night\",\n\t\t\tIconID:             \"03n\",\n\t\t\tExpectedIconString: \"\\ue33d\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Broken Clouds Display night\",\n\t\t\tIconID:             \"04n\",\n\t\t\tExpectedIconString: \"\\ue312\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Shower Rain Display night\",\n\t\t\tIconID:             \"09n\",\n\t\t\tExpectedIconString: \"\\ue319\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Rain Display night\",\n\t\t\tIconID:             \"10n\",\n\t\t\tExpectedIconString: \"\\ue325\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Thunderstorm Display night\",\n\t\t\tIconID:             \"11n\",\n\t\t\tExpectedIconString: \"\\ue32a\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Snow Display night\",\n\t\t\tIconID:             \"13n\",\n\t\t\tExpectedIconString: \"\\ue31a\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Fog Display night\",\n\t\t\tIconID:             \"50n\",\n\t\t\tExpectedIconString: \"\\ue313\",\n\t\t},\n\t}\n\n\tlocation := url.QueryEscape(\"AMSTERDAM,NL\")\n\ttestURL := fmt.Sprintf(OWMWEATHERAPIURL, location)\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\n\t\tweatherResponse := fmt.Sprintf(`{\"weather\":[{\"icon\":\"%s\"}],\"main\":{\"temp\":20.3}}`, tc.IconID)\n\t\texpectedString := fmt.Sprintf(\"%s (20°C)\", tc.ExpectedIconString)\n\n\t\tenv.On(\"HTTPRequest\", testURL).Return([]byte(weatherResponse), nil)\n\n\t\tprops := options.Map{\n\t\t\tAPIKey:   \"key\",\n\t\t\tLocation: \"AMSTERDAM,NL\",\n\t\t\tUnits:    \"metric\",\n\t\t}\n\n\t\to := &Owm{}\n\t\to.Init(props, env)\n\n\t\tassert.Nil(t, o.setStatus())\n\t\tassert.Equal(t, expectedString, renderTemplate(env, o.Template(), o), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/path.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unicode/utf8\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nconst (\n\tregexPrefix = \"re:\"\n)\n\ntype Folder struct {\n\tName    string\n\tPath    string\n\tDisplay bool\n}\n\ntype Folders []*Folder\n\nfunc (f Folders) List() []string {\n\tvar list []string\n\n\tfor _, folder := range f {\n\t\tlist = append(list, folder.Name)\n\t}\n\n\treturn list\n}\n\nfunc (f Folders) Last() *Folder {\n\treturn f[len(f)-1]\n}\n\ntype Path struct {\n\tBase\n\n\tmappedLocations map[string]string\n\troot            string\n\trelative        string\n\tpwd             string\n\tLocation        string\n\tpathSeparator   string\n\tPath            string\n\tFolders         Folders\n\tStackCount      int\n\twindowsPath     bool\n\tWritable        bool\n\tRootDir         bool\n\tcygPath         bool\n}\n\nconst (\n\t// FolderSeparatorIcon the path which is split will be separated by this icon\n\tFolderSeparatorIcon options.Option = \"folder_separator_icon\"\n\t// FolderSeparatorTemplate the path which is split will be separated by this template\n\tFolderSeparatorTemplate options.Option = \"folder_separator_template\"\n\t// HomeIcon indicates the $HOME location\n\tHomeIcon options.Option = \"home_icon\"\n\t// FolderIcon identifies one folder\n\tFolderIcon options.Option = \"folder_icon\"\n\t// WindowsRegistryIcon indicates the registry location on Windows\n\tWindowsRegistryIcon options.Option = \"windows_registry_icon\"\n\t// Agnoster displays a short path with separator icon, this the default style\n\tAgnoster string = \"agnoster\"\n\t// AgnosterFull displays all the folder names with the folder_separator_icon\n\tAgnosterFull string = \"agnoster_full\"\n\t// AgnosterShort displays the folder names with one folder_separator_icon, regardless of depth\n\tAgnosterShort string = \"agnoster_short\"\n\t// Short displays a shorter path\n\tShort string = \"short\"\n\t// Full displays the full path\n\tFull string = \"full\"\n\t// FolderType displays the current folder\n\tFolderType string = \"folder\"\n\t// Mixed like agnoster, but if a folder name is short enough, it is displayed as-is\n\tMixed string = \"mixed\"\n\t// Letter like agnoster, but with the first letter of each folder name\n\tLetter string = \"letter\"\n\t// Unique like agnoster, but with the first unique letters of each folder name\n\tUnique string = \"unique\"\n\t// AgnosterLeft like agnoster, but keeps the left side of the path\n\tAgnosterLeft string = \"agnoster_left\"\n\t// Powerlevel tries to mimic the powerlevel10k path,\n\t// used in combination with max_width.\n\tPowerlevel string = \"powerlevel\"\n\t// MixedThreshold the threshold of the length of the path Mixed will display\n\tMixedThreshold options.Option = \"mixed_threshold\"\n\t// MappedLocations allows overriding certain location with an icon\n\tMappedLocations options.Option = \"mapped_locations\"\n\t// MappedLocationsEnabled enables overriding certain locations with an icon\n\tMappedLocationsEnabled options.Option = \"mapped_locations_enabled\"\n\t// MaxDepth Maximum path depth to display without shortening\n\tMaxDepth options.Option = \"max_depth\"\n\t// MaxWidth Maximum path width to display for powerlevel style\n\tMaxWidth options.Option = \"max_width\"\n\t// Hides the root location if it doesn't fit in max_depth. Used in Agnoster Short\n\tHideRootLocation options.Option = \"hide_root_location\"\n\t// A color override cycle\n\tCycle options.Option = \"cycle\"\n\t// Color the path separators within the cycle\n\tCycleFolderSeparator options.Option = \"cycle_folder_separator\"\n\t// format to use on the folder names\n\tFolderFormat options.Option = \"folder_format\"\n\t// format to use on the first and last folder of the path\n\tEdgeFormat options.Option = \"edge_format\"\n\t// format to use on first folder of the path\n\tLeftFormat options.Option = \"left_format\"\n\t// format to use on the last folder of the path\n\tRightFormat options.Option = \"right_format\"\n\t// GitDirFormat format to use on the git directory\n\tGitDirFormat options.Option = \"gitdir_format\"\n\t// DisplayCygpath transforms the path to a cygpath format\n\tDisplayCygpath options.Option = \"display_cygpath\"\n\t// DisplayRoot indicates if the linux root slash should be displayed\n\tDisplayRoot options.Option = \"display_root\"\n\t// Fish displays the path in a fish-like style\n\tFish string = \"fish\"\n\t// DirLength the length of the directory name to display in fish style\n\tDirLength options.Option = \"dir_length\"\n\t// FullLengthDirs indicates how many full length directory names should be displayed in fish style\n\tFullLengthDirs options.Option = \"full_length_dirs\"\n)\n\nfunc (pt *Path) Template() string {\n\treturn \" {{ .Path }} \"\n}\n\nfunc (pt *Path) Enabled() bool {\n\tpt.setPaths()\n\tif pt.pwd == \"\" {\n\t\treturn false\n\t}\n\n\tpt.setStyle()\n\tpwd := pt.env.Pwd()\n\n\tpt.Location = pt.env.Flags().AbsolutePWD\n\tif pt.env.GOOS() == runtime.WINDOWS {\n\t\tpt.Location = strings.ReplaceAll(pt.Location, `\\`, `/`)\n\t}\n\n\tpt.StackCount = pt.env.StackCount()\n\tpt.Writable = pt.env.DirIsWritable(pwd)\n\treturn true\n}\n\nfunc (pt *Path) setPaths() {\n\tdefer func() {\n\t\tpt.Folders = pt.splitPath()\n\t}()\n\n\tdisplayCygpath := func() bool {\n\t\tenableCygpath := pt.options.Bool(DisplayCygpath, false)\n\t\tif !enableCygpath {\n\t\t\treturn false\n\t\t}\n\n\t\treturn pt.env.IsCygwin()\n\t}\n\n\tpt.cygPath = displayCygpath()\n\tpt.windowsPath = pt.env.GOOS() == runtime.WINDOWS && !pt.cygPath\n\n\tif pt.pathSeparator == \"\" {\n\t\tpt.pathSeparator = path.Separator()\n\t}\n\n\tpt.pwd = pt.env.Pwd()\n\tif pt.env.Shell() == shell.PWSH && len(pt.env.Flags().PSWD) != 0 {\n\t\tpt.pwd = pt.env.Flags().PSWD\n\t}\n\n\tif pt.pwd == \"\" {\n\t\treturn\n\t}\n\n\t// ensure a clean path\n\tpt.root, pt.relative = pt.replaceMappedLocations(pt.pwd)\n\tpt.pwd = pt.join(pt.root, pt.relative)\n}\n\nfunc (pt *Path) Parent() string {\n\tif pt.pwd == \"\" {\n\t\treturn \"\"\n\t}\n\n\tfolders := pt.Folders.List()\n\tif len(folders) == 0 {\n\t\t// No parent.\n\t\treturn \"\"\n\t}\n\n\tsb := text.NewBuilder()\n\n\tfolderSeparator := pt.getFolderSeparator()\n\n\tsb.WriteString(pt.root)\n\tif !pt.endWithSeparator(pt.root) {\n\t\tsb.WriteString(folderSeparator)\n\t}\n\n\tfor _, folder := range folders[:len(folders)-1] {\n\t\tsb.WriteString(folder)\n\t\tsb.WriteString(folderSeparator)\n\t}\n\n\treturn sb.String()\n}\n\nfunc (pt *Path) Format(inputPath string) string {\n\tseparator := path.Separator()\n\n\telements := strings.Split(inputPath, separator)\n\tif len(elements) == 0 {\n\t\treturn inputPath\n\t}\n\n\tif len(elements) == 1 {\n\t\treturn pt.colorizePath(elements[0], nil)\n\t}\n\n\treturn pt.colorizePath(elements[0], elements[1:])\n}\n\nfunc (pt *Path) setStyle() {\n\tif pt.relative == \"\" {\n\t\troot := pt.root\n\n\t\t// Only append a separator to a non-filesystem PSDrive root or a Windows drive root.\n\t\tif (len(pt.env.Flags().PSWD) != 0 || pt.windowsPath) && strings.HasSuffix(root, \":\") {\n\t\t\troot += pt.getFolderSeparator()\n\t\t}\n\n\t\tpt.Path = pt.colorizePath(root, nil)\n\t\treturn\n\t}\n\n\tswitch style := pt.options.String(options.Style, Agnoster); style {\n\tcase Agnoster:\n\t\tmaxWidth := pt.getMaxWidth()\n\t\tpt.Path = pt.getAgnosterPath(maxWidth)\n\tcase AgnosterFull:\n\t\tpt.Path = pt.getAgnosterFullPath()\n\tcase AgnosterShort:\n\t\tpt.Path = pt.getAgnosterShortPath()\n\tcase Mixed:\n\t\tpt.Path = pt.getMixedPath()\n\tcase Letter:\n\t\tpt.Path = pt.getLetterPath()\n\tcase Unique:\n\t\tpt.Path = pt.getUniqueLettersPath(0)\n\tcase AgnosterLeft:\n\t\tpt.Path = pt.getAgnosterLeftPath()\n\tcase Full, Short: // \"short\" is a duplicate of \"full\", just here for backwards compatibility\n\t\tpt.Path = pt.getFullPath()\n\tcase FolderType:\n\t\tpt.Path = pt.getFolderPath()\n\tcase Powerlevel:\n\t\tmaxWidth := pt.getMaxWidth()\n\t\tpt.Path = pt.getUniqueLettersPath(maxWidth)\n\tcase Fish:\n\t\tpt.Path = pt.getFishPath()\n\tdefault:\n\t\tpt.Path = fmt.Sprintf(\"Path style: %s is not available\", style)\n\t}\n\n\t// make sure we resolve all templates\n\tif txt, err := template.Render(pt.Path, pt); err == nil {\n\t\tpt.Path = txt\n\t}\n}\n\nfunc (pt *Path) getMaxWidth() int {\n\twidth := pt.options.String(MaxWidth, \"\")\n\tif width == \"\" {\n\t\treturn 0\n\t}\n\n\ttxt, err := template.Render(width, pt)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn 0\n\t}\n\n\tvalue, err := strconv.Atoi(txt)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn 0\n\t}\n\n\treturn value\n}\n\nfunc (pt *Path) getFolderSeparator() string {\n\tseparatorTemplate := pt.options.String(FolderSeparatorTemplate, \"\")\n\tif separatorTemplate == \"\" {\n\t\tseparator := pt.options.String(FolderSeparatorIcon, pt.pathSeparator)\n\t\t// if empty, use the default separator\n\t\tif separator == \"\" {\n\t\t\treturn pt.pathSeparator\n\t\t}\n\n\t\treturn separator\n\t}\n\n\ttxt, err := template.Render(separatorTemplate, pt)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tif txt == \"\" {\n\t\treturn pt.pathSeparator\n\t}\n\n\treturn txt\n}\n\nfunc (pt *Path) getMixedPath() string {\n\tthreshold := int(pt.options.Float64(MixedThreshold, 4))\n\tfolderIcon := pt.options.String(FolderIcon, \"..\")\n\n\troot, folders := pt.getPaths()\n\n\tvar elements []string\n\n\tfor i, n := 0, len(folders); i < n; i++ {\n\t\tfolderName := folders[i].Name\n\t\tif len(folderName) > threshold && i != n-1 && !folders[i].Display {\n\t\t\telements = append(elements, folderIcon)\n\t\t\tcontinue\n\t\t}\n\n\t\telements = append(elements, folderName)\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) getAgnosterPath(maxWidth int) string {\n\tif maxWidth > 0 {\n\t\treturn pt.getAgnosterMaxWidth(maxWidth)\n\t}\n\n\tfolderIcon := pt.options.String(FolderIcon, \"..\")\n\n\troot, folders := pt.getPaths()\n\n\tvar elements []string\n\n\tfor i, n := 0, len(folders); i < n; i++ {\n\t\tif folders[i].Display || i == n-1 {\n\t\t\telements = append(elements, folders[i].Name)\n\t\t\tcontinue\n\t\t}\n\n\t\telements = append(elements, folderIcon)\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) getAgnosterLeftPath() string {\n\tfolderIcon := pt.options.String(FolderIcon, \"..\")\n\n\troot, folders := pt.getPaths()\n\n\tvar elements []string\n\tif len(folders) == 0 {\n\t\treturn pt.colorizePath(root, elements)\n\t}\n\n\telements = append(elements, folders[0].Name)\n\tfor i, n := 1, len(folders); i < n; i++ {\n\t\tif folders[i].Display {\n\t\t\telements = append(elements, folders[i].Name)\n\t\t\tcontinue\n\t\t}\n\n\t\telements = append(elements, folderIcon)\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) findFirstLetterOrNumber(txt string) (letter string, index int) {\n\tfor i, char := range txt {\n\t\tif unicode.IsLetter(char) || unicode.IsNumber(char) {\n\t\t\treturn string(char), i\n\t\t}\n\t}\n\n\treturn txt, 0\n}\n\nfunc (pt *Path) getRelevantLetter(folder *Folder) string {\n\tif folder.Display {\n\t\treturn folder.Name\n\t}\n\n\tletter, index := pt.findFirstLetterOrNumber(folder.Name)\n\tif index == 0 {\n\t\treturn letter\n\t}\n\n\t// handle non-letter characters before the first found letter\n\treturn folder.Name[0:index] + letter\n}\n\nfunc (pt *Path) getLetterPath() string {\n\troot, folders := pt.getPaths()\n\n\troot = pt.getRelevantLetter(&Folder{Name: root})\n\n\tvar elements []string\n\tfor i, n := 0, len(folders); i < n; i++ {\n\t\tif folders[i].Display || i == n-1 {\n\t\t\telements = append(elements, folders[i].Name)\n\t\t\tcontinue\n\t\t}\n\n\t\tletter := pt.getRelevantLetter(folders[i])\n\t\telements = append(elements, letter)\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) getFishPath() string {\n\troot, folders := pt.getPaths()\n\tfolders = append(Folders{&Folder{Name: root, Display: false}}, folders...)\n\n\tdirLength := pt.options.Int(DirLength, 1)\n\tfullLengthDirs := max(pt.options.Int(FullLengthDirs, 1), 1)\n\n\tfolderCount := len(folders)\n\tstopAt := folderCount - fullLengthDirs\n\n\tvar elements []string\n\tfor i := range folderCount {\n\t\tname := folders[i].Name\n\t\truneCount := utf8.RuneCountInString(name)\n\t\tif folders[i].Display || dirLength <= 0 || runeCount < dirLength || i >= stopAt {\n\t\t\telements = append(elements, name)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Convert string to rune slice to properly handle multi-byte characters\n\t\trunes := []rune(name)\n\t\telements = append(elements, string(runes[:dirLength]))\n\t}\n\n\tif len(elements) == 1 {\n\t\treturn pt.colorizePath(elements[0], nil)\n\t}\n\n\treturn pt.colorizePath(elements[0], elements[1:])\n}\n\nfunc (pt *Path) getUniqueLettersPath(maxWidth int) string {\n\tdr := pt.options.Bool(DisplayRoot, false)\n\tlog.Debugf(\"%t\", dr)\n\tseparator := pt.getFolderSeparator()\n\n\troot, folders := pt.getPaths()\n\n\tfolderNames := folders.List()\n\n\tusePowerlevelStyle := func(root, relative string) bool {\n\t\tlength := len(root) + len(relative)\n\t\tif !pt.endWithSeparator(root) {\n\t\t\tlength += len(separator)\n\t\t}\n\t\treturn length <= maxWidth\n\t}\n\n\tif maxWidth > 0 {\n\t\trelative := strings.Join(folderNames, separator)\n\t\tif usePowerlevelStyle(root, relative) {\n\t\t\treturn pt.colorizePath(root, folderNames)\n\t\t}\n\t}\n\n\troot = pt.getRelevantLetter(&Folder{Name: root})\n\n\tvar elements []string\n\tletters := make(map[string]bool)\n\tletters[root] = true\n\n\tfor i, n := 0, len(folders); i < n; i++ {\n\t\tfolderName := folderNames[i]\n\n\t\tif i == n-1 {\n\t\t\telements = append(elements, folderName)\n\t\t\tbreak\n\t\t}\n\n\t\tletter := pt.getRelevantLetter(folders[i])\n\n\t\tfor letters[letter] {\n\t\t\tif letter == folderName {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tletter += folderName[len(letter) : len(letter)+1]\n\t\t}\n\n\t\tletters[letter] = true\n\t\telements = append(elements, letter)\n\n\t\t// only return early on maxWidth > 0\n\t\t// this enables the powerlevel10k behavior\n\t\tif maxWidth > 0 {\n\t\t\tlist := elements\n\t\t\tlist = append(list, folderNames[i+1:]...)\n\t\t\trelative := strings.Join(list, separator)\n\t\t\tif usePowerlevelStyle(root, relative) {\n\t\t\t\treturn pt.colorizePath(root, list)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) getAgnosterMaxWidth(maxWidth int) string {\n\tseparator := pt.getFolderSeparator()\n\tfolderIcon := pt.options.String(FolderIcon, \"..\")\n\n\troot, folders := pt.getPaths()\n\tfolderNames := append([]string{root}, folders.List()...)\n\n\t// this assumes that the root is never a single character\n\t// except when it really is / on unix systems\n\tif len(root) == 1 {\n\t\tmaxWidth++ // add one for the separator\n\t}\n\n\tif len(folderNames) == 0 {\n\t\treturn pt.colorizePath(root, nil)\n\t}\n\n\tfullPath := strings.Join(folderNames, separator)\n\n\tfor i := 0; i < len(folderNames)-1 && utf8.RuneCountInString(fullPath) > maxWidth; i++ {\n\t\tfolderNames[i] = folderIcon\n\t\tfullPath = strings.Join(folderNames, separator)\n\t}\n\n\tfor len(folderNames) > 1 && utf8.RuneCountInString(fullPath) > maxWidth {\n\t\t// remove every folder until the path is short enough\n\t\tfolderNames = folderNames[1:]\n\t\tfullPath = strings.Join(folderNames, separator)\n\t}\n\n\tif len(folderNames) == 1 {\n\t\treturn pt.colorizePath(template.TruncE(maxWidth, folderNames[0]), nil)\n\t}\n\n\treturn pt.colorizePath(folderNames[0], folderNames[1:])\n}\n\nfunc (pt *Path) getAgnosterFullPath() string {\n\troot, folders := pt.getPaths()\n\n\treturn pt.colorizePath(root, folders.List())\n}\n\nfunc (pt *Path) getAgnosterShortPath() string {\n\troot, folders := pt.getPaths()\n\n\tmaxDepth := max(pt.options.Int(MaxDepth, 1), 1)\n\n\tpathDepth := len(folders)\n\thideRootLocation := pt.options.Bool(HideRootLocation, false)\n\tfolderIcon := pt.options.String(FolderIcon, \"..\")\n\n\t// No need to shorten.\n\tif pathDepth < maxDepth || (pathDepth == maxDepth && !hideRootLocation) {\n\t\treturn pt.getAgnosterFullPath()\n\t}\n\n\telements := []string{folderIcon}\n\n\tfor i := pathDepth - maxDepth; i < pathDepth; i++ {\n\t\telements = append(elements, folders[i].Name)\n\t}\n\n\tif hideRootLocation {\n\t\treturn pt.colorizePath(elements[0], elements[1:])\n\t}\n\n\treturn pt.colorizePath(root, elements)\n}\n\nfunc (pt *Path) getFullPath() string {\n\treturn pt.colorizePath(pt.root, pt.Folders.List())\n}\n\nfunc (pt *Path) getFolderPath() string {\n\tfolderName := pt.Folders[len(pt.Folders)-1].Name\n\treturn pt.colorizePath(folderName, nil)\n}\n\nfunc (pt *Path) join(root, relative string) string {\n\t// this is a full replacement of the parent\n\tif root == \"\" {\n\t\treturn relative\n\t}\n\n\tif !pt.endWithSeparator(root) && len(relative) > 0 {\n\t\treturn root + pt.pathSeparator + relative\n\t}\n\n\treturn root + relative\n}\n\nfunc (pt *Path) setMappedLocations() {\n\tif pt.mappedLocations != nil {\n\t\treturn\n\t}\n\n\tmappedLocations := make(map[string]string)\n\n\t// predefined mapped locations, can be disabled\n\tif pt.options.Bool(MappedLocationsEnabled, true) {\n\t\tmappedLocations[\"hkcu:\"] = pt.options.String(WindowsRegistryIcon, \"\\uF013\")\n\t\tmappedLocations[\"hklm:\"] = pt.options.String(WindowsRegistryIcon, \"\\uF013\")\n\t\tmappedLocations[pt.normalize(pt.env.Home())] = pt.options.String(HomeIcon, \"~\")\n\t}\n\n\t// merge custom locations with mapped locations\n\t// mapped locations can override predefined locations\n\tkeyValues := pt.options.KeyValueMap(MappedLocations, make(map[string]string))\n\tfor key, value := range keyValues {\n\t\tif key == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tlocation, err := template.Render(key, pt)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t}\n\n\t\tif location == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif !strings.HasPrefix(location, regexPrefix) {\n\t\t\tlocation = pt.normalize(location)\n\t\t}\n\n\t\t// When two templates resolve to the same key, the values are compared in ascending order and the latter is taken.\n\t\tif v, exist := mappedLocations[location]; exist && value <= v {\n\t\t\tcontinue\n\t\t}\n\n\t\tmappedLocations[location] = value\n\t}\n\n\tpt.mappedLocations = mappedLocations\n}\n\nfunc (pt *Path) replaceMappedLocations(inputPath string) (string, string) {\n\troot, relative := pt.parsePath(inputPath)\n\tif relative == \"\" {\n\t\tpt.RootDir = true\n\t}\n\n\tpt.setMappedLocations()\n\tif len(pt.mappedLocations) == 0 {\n\t\treturn root, relative\n\t}\n\n\t// sort map keys in reverse order\n\t// fixes case when a subfoder and its parent are mapped\n\t// ex /users/test and /users/test/dev\n\tkeys := make([]string, 0, len(pt.mappedLocations))\n\tfor k := range pt.mappedLocations {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Sort(sort.Reverse(sort.StringSlice(keys)))\n\n\trootN := pt.normalize(root)\n\trelativeN := pt.normalize(relative)\n\n\tescape := func(path string) string {\n\t\t// Escape chevron characters to avoid applying unexpected text styles.\n\t\treturn strings.NewReplacer(\"<\", \"<<>\", \">\", \"<>>\").Replace(path)\n\t}\n\n\thandleRegex := func(key string) (string, bool) {\n\t\tif !strings.HasPrefix(key, regexPrefix) {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\tinput := strings.ReplaceAll(inputPath, `\\`, `/`)\n\t\tpattern := key[len(regexPrefix):]\n\n\t\t// Add (?i) at the start of the pattern for case-insensitive matching on Windows\n\t\tif pt.windowsPath || (pt.env.IsWsl() && strings.HasPrefix(input, \"/mnt/\")) {\n\t\t\tpattern = \"(?i)\" + pattern\n\t\t}\n\n\t\tmatch, OK := regex.FindStringMatch(pattern, input, 1)\n\t\tif !OK {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\t// Replace the first match with the mapped location.\n\t\tinput = strings.Replace(input, match, pt.mappedLocations[key], 1)\n\t\tinput = path.Clean(input)\n\n\t\treturn input, true\n\t}\n\n\tfor _, key := range keys {\n\t\tif input, OK := handleRegex(key); OK {\n\t\t\treturn pt.parsePath(input)\n\t\t}\n\n\t\tkeyRoot, keyRelative := pt.parsePath(key)\n\n\t\tmatchSubFolders := strings.HasSuffix(keyRelative, pt.pathSeparator+\"*\")\n\n\t\tif matchSubFolders {\n\t\t\t// Remove the trailing wildcard (*).\n\t\t\tkeyRelative = keyRelative[:len(keyRelative)-1]\n\t\t}\n\n\t\tif keyRoot != rootN || !strings.HasPrefix(relativeN, keyRelative) {\n\t\t\tcontinue\n\t\t}\n\n\t\tvalue := pt.mappedLocations[key]\n\t\toverflow := relative[len(keyRelative):]\n\n\t\t// exactly match the full path\n\t\tif overflow == \"\" {\n\t\t\treturn value, \"\"\n\t\t}\n\n\t\t// only match the root\n\t\tif keyRelative == \"\" {\n\t\t\treturn value, strings.Trim(escape(relative), pt.pathSeparator)\n\t\t}\n\n\t\t// match several prefix elements\n\t\tif matchSubFolders || overflow[:1] == pt.pathSeparator {\n\t\t\treturn value, strings.Trim(escape(overflow), pt.pathSeparator)\n\t\t}\n\t}\n\n\treturn escape(root), strings.Trim(escape(relative), pt.pathSeparator)\n}\n\n// parsePath parses a clean input path into a root and a relative.\nfunc (pt *Path) parsePath(inputPath string) (string, string) {\n\tvar root, relative string\n\n\tif inputPath == \"\" {\n\t\treturn root, relative\n\t}\n\n\tif pt.cygPath {\n\t\tcygPath, err := pt.env.RunCommand(\"cygpath\", \"-u\", inputPath)\n\t\tif len(cygPath) != 0 {\n\t\t\tinputPath = cygPath\n\t\t\tpt.pathSeparator = \"/\"\n\t\t}\n\n\t\tif err != nil {\n\t\t\tpt.cygPath = false\n\t\t\tpt.windowsPath = true\n\t\t}\n\t}\n\n\tif pt.env.GOOS() == runtime.WINDOWS {\n\t\t// Handle a UNC path, if any.\n\t\tpattern := fmt.Sprintf(`^\\%[1]s{2}(?P<hostname>[^\\%[1]s]+)\\%[1]s(?P<sharename>[^\\%[1]s]+)(\\%[1]s(?P<path>[\\s\\S]*))?$`, pt.pathSeparator)\n\t\tmatches := regex.FindNamedRegexMatch(pattern, inputPath)\n\t\tif len(matches) > 0 {\n\t\t\troot = fmt.Sprintf(`%[1]s%[1]s%[2]s%[1]s%[3]s`, pt.pathSeparator, matches[\"hostname\"], matches[\"sharename\"])\n\t\t\trelative = matches[\"path\"]\n\t\t\treturn root, relative\n\t\t}\n\t}\n\n\ts := strings.SplitAfterN(inputPath, pt.pathSeparator, 2)\n\troot = s[0]\n\n\tif len(s) == 2 {\n\t\tif len(root) > 1 {\n\t\t\troot = root[:len(root)-1]\n\t\t}\n\n\t\trelative = s[1]\n\t}\n\n\treturn root, relative\n}\n\nfunc (pt *Path) getPaths() (string, Folders) {\n\troot := pt.root\n\tfolders := pt.Folders\n\n\tisRootFS := func(inputPath string) bool {\n\t\tdisplayRoot := pt.options.Bool(DisplayRoot, false)\n\t\tif displayRoot {\n\t\t\treturn false\n\t\t}\n\n\t\treturn len(inputPath) == 1 && path.IsSeparator(inputPath[0])\n\t}\n\n\tif isRootFS(root) && len(folders) > 0 {\n\t\troot = folders[0].Name\n\t\tfolders = folders[1:]\n\t}\n\n\treturn root, folders\n}\n\nfunc (pt *Path) endWithSeparator(inputPath string) bool {\n\tif inputPath == \"\" {\n\t\treturn false\n\t}\n\n\treturn path.IsSeparator(inputPath[len(inputPath)-1])\n}\n\nfunc (pt *Path) normalize(inputPath string) string {\n\tnormalized := inputPath\n\n\tif strings.HasPrefix(normalized, \"~\") && (len(normalized) == 1 || path.IsSeparator(normalized[1])) {\n\t\tnormalized = pt.env.Home() + normalized[1:]\n\t}\n\n\tnormalized = path.Clean(normalized)\n\n\tif pt.env.GOOS() == runtime.WINDOWS || pt.env.GOOS() == runtime.DARWIN {\n\t\tnormalized = strings.ToLower(normalized)\n\t}\n\n\tif pt.cygPath {\n\t\treturn strings.ReplaceAll(normalized, `\\`, \"/\")\n\t}\n\n\treturn normalized\n}\n\nfunc (pt *Path) colorizePath(root string, elements []string) string {\n\tcycle := pt.options.StringArray(Cycle, []string{})\n\tskipColorize := len(cycle) == 0\n\tfolderSeparator := pt.getFolderSeparator()\n\tcolorSeparator := pt.options.Bool(CycleFolderSeparator, false)\n\tfolderFormat := pt.options.String(FolderFormat, \"%s\")\n\n\tedgeFormat := pt.options.String(EdgeFormat, folderFormat)\n\tleftFormat := pt.options.String(LeftFormat, edgeFormat)\n\trightFormat := pt.options.String(RightFormat, edgeFormat)\n\n\tcolorizeElement := func(element string) string {\n\t\tif skipColorize || element == \"\" {\n\t\t\treturn element\n\t\t}\n\n\t\tdefer func() {\n\t\t\tcycle = append(cycle[1:], cycle[0])\n\t\t}()\n\n\t\treturn fmt.Sprintf(\"<%s>%s</>\", cycle[0], element)\n\t}\n\n\tif len(elements) == 0 {\n\t\tformattedRoot := fmt.Sprintf(leftFormat, root)\n\t\treturn colorizeElement(formattedRoot)\n\t}\n\n\tcolorizeSeparator := func() string {\n\t\tif skipColorize || !colorSeparator {\n\t\t\treturn folderSeparator\n\t\t}\n\t\treturn fmt.Sprintf(\"<%s>%s</>\", cycle[0], folderSeparator)\n\t}\n\n\t// Pre-calculate total capacity needed\n\ttotalLen := len(root)\n\tfor _, el := range elements {\n\t\ttotalLen += len(el) + 20 // estimate for color codes\n\t}\n\n\tsb := text.NewBuilder()\n\n\tsb.Grow(totalLen)\n\n\tformattedRoot := fmt.Sprintf(leftFormat, root)\n\tsb.WriteString(colorizeElement(formattedRoot))\n\n\tif !pt.endWithSeparator(root) {\n\t\tsb.WriteString(colorizeSeparator())\n\t}\n\n\tfor i, element := range elements {\n\t\tif element == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tformat := folderFormat\n\t\tif i == len(elements)-1 {\n\t\t\tformat = rightFormat\n\t\t}\n\n\t\tformattedElement := fmt.Sprintf(format, element)\n\t\tsb.WriteString(colorizeElement(formattedElement))\n\t\tif i != len(elements)-1 {\n\t\t\tsb.WriteString(colorizeSeparator())\n\t\t}\n\t}\n\n\treturn sb.String()\n}\n\nfunc (pt *Path) splitPath() Folders {\n\tfolders := Folders{}\n\n\tif pt.relative == \"\" {\n\t\treturn folders\n\t}\n\n\telements := strings.SplitSeq(pt.relative, pt.pathSeparator)\n\tfolderFormatMap := pt.makeFolderFormatMap()\n\tcurrentPath := pt.root\n\n\tif !pt.endWithSeparator(pt.root) {\n\t\tcurrentPath += pt.pathSeparator\n\t}\n\n\tvar display bool\n\n\tfor element := range elements {\n\t\tcurrentPath += element\n\n\t\tif format := folderFormatMap[currentPath]; len(format) != 0 {\n\t\t\telement = fmt.Sprintf(format, element)\n\t\t\tdisplay = true\n\t\t}\n\n\t\tfolders = append(folders, &Folder{Name: element, Path: currentPath, Display: display})\n\n\t\tcurrentPath += pt.pathSeparator\n\n\t\tdisplay = false\n\t}\n\n\treturn folders\n}\n\nfunc (pt *Path) makeFolderFormatMap() map[string]string {\n\tfolderFormatMap := make(map[string]string)\n\n\tif gitDirFormat := pt.options.String(GitDirFormat, \"\"); len(gitDirFormat) != 0 {\n\t\tdir, err := pt.env.HasParentFilePath(\".git\", false)\n\t\tif err == nil && dir.IsDir {\n\t\t\t// Make it consistent with the modified parent.\n\t\t\tparent := pt.join(pt.replaceMappedLocations(dir.ParentFolder))\n\t\t\tfolderFormatMap[parent] = gitDirFormat\n\t\t}\n\t}\n\n\treturn folderFormatMap\n}\n"
  },
  {
    "path": "src/segments/path_test.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\nconst (\n\thomeDir        = \"/home/someone\"\n\thomeDirWindows = \"C:\\\\Users\\\\someone\"\n)\n\nfunc renderTemplateNoTrimSpace(env *mock.Environment, segmentTemplate string, context any) string {\n\tenv.On(\"Shell\").Return(\"foo\")\n\n\tif template.Cache == nil {\n\t\ttemplate.Cache = &cache.Template{}\n\t}\n\ttemplate.Init(env, nil, nil)\n\n\ttext, err := template.Render(segmentTemplate, context)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\n\treturn text\n}\n\nfunc renderTemplate(env *mock.Environment, segmentTemplate string, context any) string {\n\treturn strings.TrimSpace(renderTemplateNoTrimSpace(env, segmentTemplate, context))\n}\n\ntype testParentCase struct {\n\tCase                string\n\tExpected            string\n\tHomePath            string\n\tPwd                 string\n\tGOOS                string\n\tPathSeparator       string\n\tFolderSeparatorIcon string\n}\n\nfunc TestParent(t *testing.T) {\n\tfor _, tc := range testParentCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(tc.HomePath)\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{})\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\n\t\tprops := options.Map{\n\t\t\tFolderSeparatorIcon: tc.FolderSeparatorIcon,\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\n\t\tgot := path.Parent()\n\t\tassert.EqualValues(t, tc.Expected, got, tc.Case)\n\t}\n}\n\ntype testAgnosterPathStyleCase struct {\n\tCygpathError        error\n\tGOOS                string\n\tShell               string\n\tPswd                string\n\tPwd                 string\n\tPathSeparator       string\n\tHomeIcon            string\n\tHomePath            string\n\tStyle               string\n\tFolderSeparatorIcon string\n\tCygpath             string\n\tExpected            string\n\tMaxDepth            int\n\tMaxWidth            int\n\tHideRootLocation    bool\n\tCygwin              bool\n\tDisplayRoot         bool\n}\n\nfunc TestAgnosterPathStyles(t *testing.T) {\n\tfor _, tc := range testAgnosterPathStyleCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tenv.On(\"Home\").Return(tc.HomePath)\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\tenv.On(\"IsCygwin\").Return(tc.Cygwin)\n\t\tenv.On(\"StackCount\").Return(0)\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.Pswd,\n\t\t}\n\t\tenv.On(\"Flags\").Return(args)\n\n\t\tif tc.Shell == \"\" {\n\t\t\ttc.Shell = shell.PWSH\n\t\t}\n\t\tenv.On(\"Shell\").Return(tc.Shell)\n\n\t\tdisplayCygpath := tc.Cygwin\n\t\tif displayCygpath {\n\t\t\tenv.On(\"RunCommand\", \"cygpath\", []string{\"-u\", tc.Pwd}).Return(tc.Cygpath, tc.CygpathError)\n\t\t\tenv.On(\"RunCommand\", \"cygpath\", testify_.Anything).Return(\"brrrr\", nil)\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\tFolderSeparatorIcon: tc.FolderSeparatorIcon,\n\t\t\toptions.Style:       tc.Style,\n\t\t\tMaxDepth:            tc.MaxDepth,\n\t\t\tMaxWidth:            tc.MaxWidth,\n\t\t\tHideRootLocation:    tc.HideRootLocation,\n\t\t\tDisplayCygpath:      displayCygpath,\n\t\t\tDisplayRoot:         tc.DisplayRoot,\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tpath.setStyle()\n\t\tgot := renderTemplateNoTrimSpace(env, \"{{ .Path }}\", path)\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\ntype testFullAndFolderPathCase struct {\n\tStyle                  string\n\tHomePath               string\n\tFolderSeparatorIcon    string\n\tPwd                    string\n\tPswd                   string\n\tExpected               string\n\tGOOS                   string\n\tPathSeparator          string\n\tTemplate               string\n\tStackCount             int\n\tDisableMappedLocations bool\n}\n\nfunc TestFullAndFolderPath(t *testing.T) {\n\tfor _, tc := range testFullAndFolderPathCases {\n\t\tenv := new(mock.Environment)\n\t\tif tc.PathSeparator == \"\" {\n\t\t\ttc.PathSeparator = \"/\"\n\t\t}\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tif tc.GOOS == runtime.WINDOWS {\n\t\t\tenv.On(\"Home\").Return(homeDirWindows)\n\t\t} else {\n\t\t\tenv.On(\"Home\").Return(homeDir)\n\t\t}\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\tenv.On(\"StackCount\").Return(tc.StackCount)\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.Pswd,\n\t\t}\n\t\tenv.On(\"Flags\").Return(args)\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = \"{{ if gt .StackCount 0 }}{{ .StackCount }} {{ end }}{{ .Path }}\"\n\t\t}\n\t\tprops := options.Map{\n\t\t\toptions.Style: tc.Style,\n\t\t}\n\t\tif tc.FolderSeparatorIcon != \"\" {\n\t\t\tprops[FolderSeparatorIcon] = tc.FolderSeparatorIcon\n\t\t}\n\t\tif tc.DisableMappedLocations {\n\t\t\tprops[MappedLocationsEnabled] = false\n\t\t}\n\n\t\tpath := &Path{\n\t\t\tStackCount: env.StackCount(),\n\t\t}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tpath.setStyle()\n\t\tgot := renderTemplateNoTrimSpace(env, tc.Template, path)\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\ntype testFullPathCustomMappedLocationsCase struct {\n\tPwd             string\n\tMappedLocations map[string]string\n\tGOOS            string\n\tPathSeparator   string\n\tExpected        string\n}\n\nfunc TestFullPathCustomMappedLocations(t *testing.T) {\n\tfor _, tc := range testFullPathCustomMappedLocationsCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(homeDir)\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\n\t\tif tc.GOOS == \"\" {\n\t\t\ttc.GOOS = runtime.DARWIN\n\t\t}\n\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\n\t\tif tc.PathSeparator == \"\" {\n\t\t\ttc.PathSeparator = \"/\"\n\t\t}\n\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.Pwd,\n\t\t}\n\n\t\tenv.On(\"Flags\").Return(args)\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\t\tenv.On(\"Getenv\", \"HOME\").Return(homeDir)\n\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tprops := options.Map{\n\t\t\toptions.Style:          Full,\n\t\t\tMappedLocationsEnabled: false,\n\t\t\tMappedLocations:        tc.MappedLocations,\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tpath.setStyle()\n\n\t\tgot := renderTemplateNoTrimSpace(env, \"{{ .Path }}\", path)\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\ntype testAgnosterPathCase struct {\n\tCase           string\n\tExpected       string\n\tHome           string\n\tPWD            string\n\tGOOS           string\n\tPathSeparator  string\n\tCycle          []string\n\tColorSeparator bool\n}\n\nfunc TestAgnosterPath(t *testing.T) {\n\tfor _, tc := range testAgnosterPathCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(tc.Home)\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tenv.On(\"Pwd\").Return(tc.PWD)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.PWD,\n\t\t}\n\t\tenv.On(\"Flags\").Return(args)\n\t\tenv.On(\"Shell\").Return(shell.PWSH)\n\n\t\tprops := options.Map{\n\t\t\toptions.Style:        Agnoster,\n\t\t\tFolderSeparatorIcon:  \" > \",\n\t\t\tFolderIcon:           \"f\",\n\t\t\tHomeIcon:             \"~\",\n\t\t\tCycle:                tc.Cycle,\n\t\t\tCycleFolderSeparator: tc.ColorSeparator,\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tpath.setStyle()\n\t\tgot := renderTemplateNoTrimSpace(env, \"{{ .Path }}\", path)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\ntype testAgnosterLeftPathCase struct {\n\tCase          string\n\tExpected      string\n\tHome          string\n\tPWD           string\n\tGOOS          string\n\tPathSeparator string\n}\n\nfunc TestAgnosterLeftPath(t *testing.T) {\n\tfor _, tc := range testAgnosterLeftPathCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(tc.Home)\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\t\tenv.On(\"Pwd\").Return(tc.PWD)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.PWD,\n\t\t}\n\t\tenv.On(\"Flags\").Return(args)\n\t\tenv.On(\"Shell\").Return(shell.PWSH)\n\n\t\tprops := options.Map{\n\t\t\toptions.Style:       AgnosterLeft,\n\t\t\tFolderSeparatorIcon: \" > \",\n\t\t\tFolderIcon:          \"f\",\n\t\t\tHomeIcon:            \"~\",\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tpath.setStyle()\n\t\tgot := renderTemplateNoTrimSpace(env, \"{{ .Path }}\", path)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGetFolderSeparator(t *testing.T) {\n\tcases := []struct {\n\t\tCase                    string\n\t\tFolderSeparatorIcon     string\n\t\tFolderSeparatorTemplate string\n\t\tExpected                string\n\t}{\n\t\t{Case: \"default\", Expected: \"/\"},\n\t\t{Case: \"icon - no template\", FolderSeparatorIcon: \"\\ue5fe\", Expected: \"\\ue5fe\"},\n\t\t{Case: \"template\", FolderSeparatorTemplate: \"{{ if eq .Shell \\\"bash\\\" }}\\\\{{ end }}\", Expected: \"\\\\\"},\n\t\t{Case: \"template empty\", FolderSeparatorTemplate: \"{{ if eq .Shell \\\"pwsh\\\" }}\\\\{{ end }}\", Expected: \"/\"},\n\t\t{Case: \"invalid template\", FolderSeparatorTemplate: \"{{ if eq .Shell \\\"pwsh\\\" }}\", Expected: \"/\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tShell: \"bash\",\n\t\t\t},\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tprops := options.Map{}\n\n\t\tif len(tc.FolderSeparatorTemplate) > 0 {\n\t\t\tprops[FolderSeparatorTemplate] = tc.FolderSeparatorTemplate\n\t\t}\n\n\t\tif len(tc.FolderSeparatorIcon) > 0 {\n\t\t\tprops[FolderSeparatorIcon] = tc.FolderSeparatorIcon\n\t\t}\n\n\t\tpath := &Path{\n\t\t\tpathSeparator: \"/\",\n\t\t}\n\t\tpath.Init(props, env)\n\n\t\tgot := path.getFolderSeparator()\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\ntype testNormalizePathCase struct {\n\tCase          string\n\tInput         string\n\tHomeDir       string\n\tGOOS          string\n\tPathSeparator string\n\tExpected      string\n\tCygwin        bool\n}\n\nfunc TestNormalizePath(t *testing.T) {\n\tfor _, tc := range testNormalizePathCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(tc.HomeDir)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\n\t\tif tc.PathSeparator == \"\" {\n\t\t\ttc.PathSeparator = \"/\"\n\t\t}\n\n\t\tenv.On(\"PathSeparator\").Return(tc.PathSeparator)\n\n\t\tpt := &Path{cygPath: tc.Cygwin}\n\t\tpt.Init(options.Map{}, env)\n\n\t\tgot := pt.normalize(tc.Input)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\ntype testSplitPathCase struct {\n\tCase         string\n\tGOOS         string\n\tRelative     string\n\tRoot         string\n\tGitDir       *runtime.FileInfo\n\tGitDirFormat string\n\tExpected     Folders\n}\n\nfunc TestSplitPath(t *testing.T) {\n\tfor _, tc := range testSplitPathCases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Home\").Return(\"/a/b\")\n\t\tenv.On(\"HasParentFilePath\", \".git\", false).Return(tc.GitDir, nil)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\n\t\tprops := options.Map{\n\t\t\tGitDirFormat: tc.GitDirFormat,\n\t\t}\n\n\t\tpath := &Path{\n\t\t\troot:          tc.Root,\n\t\t\trelative:      tc.Relative,\n\t\t\tpathSeparator: \"/\",\n\t\t\twindowsPath:   tc.GOOS == runtime.WINDOWS,\n\t\t}\n\t\tpath.Init(props, env)\n\n\t\tgot := path.splitPath()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestGetMaxWidth(t *testing.T) {\n\tcases := []struct {\n\t\tMaxWidth any\n\t\tCase     string\n\t\tExpected int\n\t}{\n\t\t{\n\t\t\tCase:     \"Nil\",\n\t\t\tExpected: 0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Empty string\",\n\t\t\tMaxWidth: \"\",\n\t\t\tExpected: 0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Invalid template\",\n\t\t\tMaxWidth: \"{{ .Unknown }}\",\n\t\t\tExpected: 0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Environment variable\",\n\t\t\tMaxWidth: \"{{ .Env.MAX_WIDTH }}\",\n\t\t\tExpected: 120,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", \"MAX_WIDTH\").Return(\"120\")\n\t\tenv.On(\"Shell\").Return(shell.BASH)\n\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tprops := options.Map{\n\t\t\tMaxWidth: tc.MaxWidth,\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tgot := path.getMaxWidth()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestAgnosterMaxWidth(t *testing.T) {\n\tcases := []struct {\n\t\tname        string\n\t\tpwd         string\n\t\tfolderIcon  string\n\t\tseparator   string\n\t\texpected    string\n\t\tgoos        string\n\t\tmaxWidth    int\n\t\tdisplayRoot bool\n\t}{\n\t\t{\n\t\t\tname:        \"path shorter than maxWidth\",\n\t\t\tpwd:         \"/foob/user/docs\",\n\t\t\tmaxWidth:    20,\n\t\t\tdisplayRoot: false,\n\t\t\tseparator:   \"/\",\n\t\t\tfolderIcon:  `..`,\n\t\t\texpected:    \"foob/user/docs\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"path shorter than maxWidth, Windows\",\n\t\t\tpwd:         `C:\\Users\\john\\Documents`,\n\t\t\tmaxWidth:    20,\n\t\t\tdisplayRoot: true,\n\t\t\tfolderIcon:  `..`,\n\t\t\tseparator:   `\\`,\n\t\t\texpected:    `..\\..\\john\\Documents`,\n\t\t\tgoos:        runtime.WINDOWS,\n\t\t},\n\t\t{\n\t\t\tname:        \"path shorter than maxWidth, wth root\",\n\t\t\tpwd:         \"/foob/user/docs\",\n\t\t\tmaxWidth:    20,\n\t\t\tdisplayRoot: true,\n\t\t\tfolderIcon:  `..`,\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"/foob/user/docs\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"path exactly maxWidth\",\n\t\t\tpwd:         \"/foob/user/docs\",\n\t\t\tmaxWidth:    15,\n\t\t\tdisplayRoot: true,\n\t\t\tfolderIcon:  `..`,\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"/foob/user/docs\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"path longer than maxWidth with folder icons\",\n\t\t\tpwd:         \"/foob/user/documents/projects\",\n\t\t\tmaxWidth:    15,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"..\",\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"../../projects\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"very long path requiring multiple folder replacements\",\n\t\t\tpwd:         \"/foob/user/documents/projects/myproject/src/main\",\n\t\t\tmaxWidth:    21,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"..\",\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"../../../../../main\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"path requiring final folder truncation\",\n\t\t\tpwd:         \"/foob/verylongfoldername\",\n\t\t\tmaxWidth:    15,\n\t\t\tdisplayRoot: false,\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"verylongfolder…\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"Windows path with custom separator\",\n\t\t\tpwd:         `C:\\Users\\john\\Documents`,\n\t\t\tmaxWidth:    15,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"…\",\n\t\t\tseparator:   `\\`,\n\t\t\texpected:    `…\\…\\…\\Documents`,\n\t\t\tgoos:        runtime.WINDOWS,\n\t\t},\n\t\t{\n\t\t\tname:        \"single folder path\",\n\t\t\tpwd:         \"/foob\",\n\t\t\tmaxWidth:    10,\n\t\t\tdisplayRoot: false,\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"foob\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"empty relative path\",\n\t\t\tpwd:         \"/\",\n\t\t\tmaxWidth:    10,\n\t\t\tdisplayRoot: true,\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"/\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"custom folder icon\",\n\t\t\tpwd:         \"/foob/user/documents/projects\",\n\t\t\tmaxWidth:    15,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"⋯\",\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"⋯/⋯/⋯/projects\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"maxwidth is smaller than folder name\",\n\t\t\tpwd:         \"/foob/user/documents/projects\",\n\t\t\tmaxWidth:    2,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"⋯\",\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"p…\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tname:        \"maxwidth is 0\",\n\t\t\tpwd:         \"/foob/user/documents/projects\",\n\t\t\tmaxWidth:    0,\n\t\t\tdisplayRoot: false,\n\t\t\tfolderIcon:  \"⋯\",\n\t\t\tseparator:   \"/\",\n\t\t\texpected:    \"…\",\n\t\t\tgoos:        runtime.LINUX,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tenv := &mock.Environment{}\n\t\t\tenv.On(\"Pwd\").Return(tc.pwd)\n\t\t\tenv.On(\"Home\").Return(\"/home\")\n\t\t\tenv.On(\"GOOS\").Return(tc.goos)\n\t\t\tenv.On(\"Shell\").Return(shell.BASH)\n\n\t\t\tpath := &Path{\n\t\t\t\tBase: Base{\n\t\t\t\t\tenv: env,\n\t\t\t\t\toptions: options.Map{\n\t\t\t\t\t\tDisplayRoot:         tc.displayRoot,\n\t\t\t\t\t\tFolderIcon:          tc.folderIcon,\n\t\t\t\t\t\tFolderSeparatorIcon: tc.separator,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpathSeparator: tc.separator,\n\t\t\t}\n\n\t\t\t// Set up the path state\n\t\t\tpath.setPaths()\n\n\t\t\tgot := path.getAgnosterMaxWidth(tc.maxWidth)\n\t\t\tassert.Equal(t, tc.expected, got, tc.name)\n\t\t})\n\t}\n}\n\nfunc TestFishPath(t *testing.T) {\n\tcases := []struct {\n\t\tname           string\n\t\tpwd            string\n\t\tseparator      string\n\t\tgoos           string\n\t\texpected       string\n\t\tdirLength      int\n\t\tfullLengthDirs int\n\t}{\n\t\t{\n\t\t\tname:           \"default settings\",\n\t\t\tpwd:            \"/home/user/documents/projects\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"h/u/d/projects\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length 2\",\n\t\t\tpwd:            \"/home/user/documents/projects\",\n\t\t\tdirLength:      2,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"ho/us/do/projects\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"full length dirs 2\",\n\t\t\tpwd:            \"/home/user/documents/projects/myproject\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 2,\n\t\t\texpected:       \"h/u/d/projects/myproject\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length 3, full length dirs 2\",\n\t\t\tpwd:            \"/home/user/documents/projects/myproject\",\n\t\t\tdirLength:      3,\n\t\t\tfullLengthDirs: 2,\n\t\t\texpected:       \"hom/use/doc/projects/myproject\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"full length dirs 2 - Windows\",\n\t\t\tpwd:            `C:\\Users\\Jan\\Documents\\Projects\\Myproject`,\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 2,\n\t\t\texpected:       `C\\U\\J\\D\\Projects\\Myproject`,\n\t\t\tseparator:      `\\`,\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length 3, full length dirs 2 - Windows\",\n\t\t\tpwd:            `C:\\Users\\Jan\\Documents\\Projects\\Myproject`,\n\t\t\tdirLength:      3,\n\t\t\tfullLengthDirs: 2,\n\t\t\texpected:       `C:\\Use\\Jan\\Doc\\Projects\\Myproject`,\n\t\t\tseparator:      `\\`,\n\t\t},\n\t\t{\n\t\t\tname:           \"single folder\",\n\t\t\tpwd:            \"/home\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"home\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"two folders with full length dirs 1\",\n\t\t\tpwd:            \"/home/user\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"h/user\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"root only\",\n\t\t\tpwd:            \"/\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"/\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length 0 should disable shortening\",\n\t\t\tpwd:            \"/home/user/documents\",\n\t\t\tdirLength:      0,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"home/user/documents\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length negative should disable shortening\",\n\t\t\tpwd:            \"/home/user/documents\",\n\t\t\tdirLength:      -1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"home/user/documents\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"full length dirs 0 should fallback to 1\",\n\t\t\tpwd:            \"/home/user/documents\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 0,\n\t\t\texpected:       \"h/u/documents\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"full length dirs negative should fallback to 1\",\n\t\t\tpwd:            \"/home/user/documents\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: -1,\n\t\t\texpected:       \"h/u/documents\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"full length dirs greater than total folders\",\n\t\t\tpwd:            \"/home/user\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 5,\n\t\t\texpected:       \"home/user\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"dir length greater than folder name\",\n\t\t\tpwd:            \"/a/b/c\",\n\t\t\tdirLength:      10,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"a/b/c\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"multi-byte unicode home icon\",\n\t\t\tpwd:            \"/󰋜/Downloads/test\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"󰋜/D/test\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"multi-byte unicode home icon with dir length 2\",\n\t\t\tpwd:            \"/󰋜/Documents/Projects\",\n\t\t\tdirLength:      2,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"󰋜/Do/Projects\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"path with emoji folders\",\n\t\t\tpwd:            \"/🏠/📁/💻\",\n\t\t\tdirLength:      1,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"🏠/📁/💻\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t\t{\n\t\t\tname:           \"mixed multi-byte and ascii\",\n\t\t\tpwd:            \"/󰋜test/normal/󰨳end\",\n\t\t\tdirLength:      2,\n\t\t\tfullLengthDirs: 1,\n\t\t\texpected:       \"󰋜t/no/󰨳end\",\n\t\t\tseparator:      \"/\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tenv := &mock.Environment{}\n\t\t\tenv.On(\"Pwd\").Return(tc.pwd)\n\t\t\tenv.On(\"Home\").Return(\"/foob\")\n\t\t\tenv.On(\"GOOS\").Return(tc.goos)\n\t\t\tenv.On(\"Shell\").Return(shell.BASH)\n\n\t\t\tpath := &Path{\n\t\t\t\tBase: Base{\n\t\t\t\t\tenv: env,\n\t\t\t\t\toptions: options.Map{\n\t\t\t\t\t\tDirLength:      tc.dirLength,\n\t\t\t\t\t\tFullLengthDirs: tc.fullLengthDirs,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpathSeparator: tc.separator,\n\t\t\t}\n\n\t\t\tpath.setPaths()\n\t\t\tresult := path.getFishPath()\n\n\t\t\tassert.Equal(t, result, tc.expected, tc.name)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/segments/path_unix_test.go",
    "content": "//go:build !windows\n\npackage segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tabc   = \"/abc\"\n\tabcd  = \"/a/b/c/d\"\n\tcdefg = \"/c/d/e/f/g\"\n)\n\nvar testParentCases = []testParentCase{\n\t{\n\t\tCase:          \"Inside Home folder\",\n\t\tExpected:      \"~/\",\n\t\tHomePath:      homeDir,\n\t\tPwd:           homeDir + \"/test\",\n\t\tGOOS:          runtime.DARWIN,\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Home folder\",\n\t\tHomePath:      homeDir,\n\t\tPwd:           homeDir,\n\t\tGOOS:          runtime.DARWIN,\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Home folder with a trailing separator\",\n\t\tHomePath:      homeDir,\n\t\tPwd:           homeDir + \"/\",\n\t\tGOOS:          runtime.DARWIN,\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Root\",\n\t\tHomePath:      homeDir,\n\t\tPwd:           \"/\",\n\t\tGOOS:          runtime.DARWIN,\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Root + 1\",\n\t\tExpected:      \"/\",\n\t\tHomePath:      homeDir,\n\t\tPwd:           \"/usr\",\n\t\tGOOS:          runtime.DARWIN,\n\t\tPathSeparator: \"/\",\n\t},\n}\n\nvar testAgnosterPathStyleCases = []testAgnosterPathStyleCase{\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"~ > a > ab > abcd\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/ab/abc/abcd\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"~ > a > .a > abcd\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/ab/.abc/abcd\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"~ > a > ab > abcd\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/ab/ab/abcd\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"a\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/ab\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"/a > c > ef\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/ab/cd/ef\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tDisplayRoot:         true,\n\t},\n\n\t{\n\t\tStyle:               Powerlevel,\n\t\tExpected:            \"t > w > o > a > v > l > p > wh > we > i > wa > th > the > d > f > u > it > c > to > a > co > stream\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/there/was/once/a/very/long/path/which/wended/its/way/through/the/dark/forest/until/it/came/to/a/cold/stream\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxWidth:            20,\n\t},\n\t{\n\t\tStyle:               Powerlevel,\n\t\tExpected:            \"t > w > o > a > v > l > p > which > wended > its > way > through > the\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/there/was/once/a/very/long/path/which/wended/its/way/through/the\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxWidth:            70,\n\t},\n\t{\n\t\tStyle:               Powerlevel,\n\t\tExpected:            \"var/cache/pacman\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/var/cache/pacman\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \"/\",\n\t\tMaxWidth:            50,\n\t},\n\t{\n\t\tStyle:               Powerlevel,\n\t\tExpected:            \"/var/cache/pacman\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/var/cache/pacman\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \"/\",\n\t\tMaxWidth:            50,\n\t\tDisplayRoot:         true,\n\t},\n\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"~\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir,\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"~ > a > w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/ab/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > b > a > w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/burp/ab/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > a > w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/ab/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > a > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/ab/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > a > ._w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/ab/._whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .ä > ū > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.äufbau/ūmgebung/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > 1 > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/12345/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > 1 > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/12345abc/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"u > .b > __p > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/.burp/__pycache__/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"➼ > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/➼/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"➼ s > .w > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/➼ something/.whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"w\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/whatever\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"~ > .. > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"~ > ab > .. > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/ab/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"usr > foo > bar > .. > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/foo/bar/foobar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"whatever > .. > foo > bar\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/whatever/foobar/foo/bar\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterFull,\n\t\tExpected:            \"usr > location > whatever\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/location/whatever\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterFull,\n\t\tExpected:            \"PSDRIVE: | src\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/foo\",\n\t\tPswd:                \"PSDRIVE:/src\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t},\n\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. | src | init\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/foo\",\n\t\tPswd:                \"PSDRIVE:/src/init\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"usr > foo > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/foo/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"PSDRIVE: | src\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/foo\",\n\t\tPswd:                \"PSDRIVE:/src\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > projects\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/projects\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir,\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            1,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"usr > .. > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/foo/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > .. > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"usr > .. > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/location/whatever/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > .. > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/foo/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > foo > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/foo/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"PSDRIVE: | .. | init\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/foo\",\n\t\tPswd:                \"PSDRIVE:/src/init\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. > foo\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/foo\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            1,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. > foo > bar > man\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/usr/foo/bar/man\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > foo\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/foo\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > foo > bar\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/foo/bar\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"C: | \",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 \"/mnt/c\",\n\t\tPswd:                \"C:\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ | space foo\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/space foo\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. | space foo\",\n\t\tHomePath:            homeDir,\n\t\tPwd:                 homeDir + \"/space foo\",\n\t\tPathSeparator:       \"/\",\n\t\tFolderSeparatorIcon: \" | \",\n\t\tMaxDepth:            1,\n\t\tHideRootLocation:    true,\n\t},\n}\n\nvar testAgnosterPathCases = []testAgnosterPathCase{\n\t{\n\t\tCase:          \"Unix outside home\",\n\t\tExpected:      \"mnt > f > f > location\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/go/test/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix inside home\",\n\t\tExpected:      \"~ > f > f > location\",\n\t\tHome:          homeDir,\n\t\tPWD:           homeDir + \"/docs/jan/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix outside home zero levels\",\n\t\tExpected:      \"mnt > location\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix outside home one level\",\n\t\tExpected:      \"mnt > f > location\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/folder/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix, colorize\",\n\t\tExpected:      \"<blue>mnt</> > <yellow>f</> > <blue>location</>\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/folder/location\",\n\t\tPathSeparator: \"/\",\n\t\tCycle:         []string{\"blue\", \"yellow\"},\n\t},\n\t{\n\t\tCase:           \"Unix, colorize with folder separator\",\n\t\tExpected:       \"<blue>mnt</><yellow> > </><yellow>f</><blue> > </><blue>location</>\",\n\t\tHome:           homeDir,\n\t\tPWD:            \"/mnt/folder/location\",\n\t\tPathSeparator:  \"/\",\n\t\tCycle:          []string{\"blue\", \"yellow\"},\n\t\tColorSeparator: true,\n\t},\n\t{\n\t\tCase:          \"Unix one level\",\n\t\tExpected:      \"mnt\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt\",\n\t\tPathSeparator: \"/\",\n\t},\n}\n\nvar testAgnosterLeftPathCases = []testAgnosterLeftPathCase{\n\t{\n\t\tCase:          \"Unix outside home\",\n\t\tExpected:      \"mnt > go > f > f\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/go/test/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix inside home\",\n\t\tExpected:      \"~ > docs > f > f\",\n\t\tHome:          homeDir,\n\t\tPWD:           homeDir + \"/docs/jan/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix outside home zero levels\",\n\t\tExpected:      \"mnt > location\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/location\",\n\t\tPathSeparator: \"/\",\n\t},\n\t{\n\t\tCase:          \"Unix outside home one level\",\n\t\tExpected:      \"mnt > folder > f\",\n\t\tHome:          homeDir,\n\t\tPWD:           \"/mnt/folder/location\",\n\t\tPathSeparator: \"/\",\n\t},\n}\n\nvar testFullAndFolderPathCases = []testFullAndFolderPathCase{\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", Expected: \"/\"},\n\t{Style: Full, Pwd: \"/\", Expected: \"/\"},\n\t{Style: Full, Pwd: homeDir, Expected: \"~\"},\n\t{Style: Full, Pwd: homeDir + abc, Expected: \"~/abc\"},\n\t{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, Expected: abcd},\n\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: homeDir, Expected: \"~\"},\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: homeDir, Expected: \"/home|someone\", DisableMappedLocations: true},\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: homeDir + abc, Expected: \"~|abc\"},\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: abcd, Expected: \"/a|b|c|d\"},\n\n\t{Style: FolderType, Pwd: \"/\", Expected: \"/\"},\n\t{Style: FolderType, Pwd: homeDir, Expected: \"~\"},\n\t{Style: FolderType, Pwd: homeDir, Expected: \"someone\", DisableMappedLocations: true},\n\t{Style: FolderType, Pwd: homeDir + abc, Expected: \"abc\"},\n\t{Style: FolderType, Pwd: abcd, Expected: \"d\"},\n\n\t{Style: FolderType, FolderSeparatorIcon: \"|\", Pwd: \"/\", Expected: \"/\"},\n\t{Style: FolderType, FolderSeparatorIcon: \"|\", Pwd: homeDir, Expected: \"~\"},\n\t{Style: FolderType, FolderSeparatorIcon: \"|\", Pwd: homeDir, Expected: \"someone\", DisableMappedLocations: true},\n\t{Style: FolderType, FolderSeparatorIcon: \"|\", Pwd: homeDir + abc, Expected: \"abc\"},\n\t{Style: FolderType, FolderSeparatorIcon: \"|\", Pwd: abcd, Expected: \"d\"},\n\n\t// StackCountEnabled=true and StackCount=2\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", StackCount: 2, Expected: \"2 /\"},\n\t{Style: Full, Pwd: \"/\", StackCount: 2, Expected: \"2 /\"},\n\t{Style: Full, Pwd: homeDir, StackCount: 2, Expected: \"2 ~\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: \"2 ~/abc\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: 2, Expected: \"2 \" + homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, StackCount: 2, Expected: \"2 /a/b/c/d\"},\n\n\t// StackCountEnabled=false and StackCount=2\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", Template: \"{{ .Path }}\", StackCount: 2, Expected: \"/\"},\n\t{Style: Full, Pwd: \"/\", Template: \"{{ .Path }}\", StackCount: 2, Expected: \"/\"},\n\t{Style: Full, Pwd: homeDir, Template: \"{{ .Path }}\", StackCount: 2, Expected: \"~\"},\n\n\t{Style: Full, Pwd: homeDir + abc, Template: \"{{ .Path }}\", StackCount: 2, Expected: homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, Template: \"{{ .Path }}\", StackCount: 2, Expected: abcd},\n\n\t// StackCountEnabled=true and StackCount=0\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", StackCount: 0, Expected: \"/\"},\n\t{Style: Full, Pwd: \"/\", StackCount: 0, Expected: \"/\"},\n\t{Style: Full, Pwd: homeDir, StackCount: 0, Expected: \"~\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: \"~/abc\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: 0, Expected: homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, StackCount: 0, Expected: abcd},\n\n\t// StackCountEnabled=true and StackCount<0\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", StackCount: -1, Expected: \"/\"},\n\t{Style: Full, Pwd: \"/\", StackCount: -1, Expected: \"/\"},\n\t{Style: Full, Pwd: homeDir, StackCount: -1, Expected: \"~\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: \"~/abc\"},\n\t{Style: Full, Pwd: homeDir + abc, StackCount: -1, Expected: homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, StackCount: -1, Expected: abcd},\n\n\t// StackCountEnabled=true and StackCount not set\n\t{Style: Full, FolderSeparatorIcon: \"|\", Pwd: \"/\", Expected: \"/\"},\n\t{Style: Full, Pwd: \"/\", Expected: \"/\"},\n\t{Style: Full, Pwd: homeDir, Expected: \"~\"},\n\t{Style: Full, Pwd: homeDir + abc, Expected: \"~/abc\"},\n\t{Style: Full, Pwd: homeDir + abc, Expected: homeDir + abc, DisableMappedLocations: true},\n\t{Style: Full, Pwd: abcd, Expected: abcd},\n}\n\nvar testFullPathCustomMappedLocationsCases = []testFullPathCustomMappedLocationsCase{\n\t{Pwd: homeDir + \"/d\", MappedLocations: map[string]string{\"{{ .Env.HOME }}/d\": \"#\"}, Expected: \"#\"},\n\t{Pwd: abcd, MappedLocations: map[string]string{abcd: \"#\"}, Expected: \"#\"},\n\t{Pwd: abcd, MappedLocations: map[string]string{\"/a/b\": \"#\"}, Expected: \"#/c/d\"},\n\t{Pwd: abcd, MappedLocations: map[string]string{\"/a/b\": \"/e/f\"}, Expected: \"/e/f/c/d\"},\n\t{Pwd: homeDir + abcd, MappedLocations: map[string]string{\"~/a/b\": \"#\"}, Expected: \"#/c/d\"},\n\t{Pwd: \"/a\" + homeDir + \"/b/c/d\", MappedLocations: map[string]string{\"/a~\": \"#\"}, Expected: \"/a\" + homeDir + \"/b/c/d\"},\n\t{Pwd: homeDir + abcd, MappedLocations: map[string]string{\"/a/b\": \"#\"}, Expected: homeDir + abcd},\n}\n\nvar testSplitPathCases = []testSplitPathCase{\n\t{Case: \"Root directory\", Root: \"/\", Expected: Folders{}},\n\t{\n\t\tCase:     \"Regular directory\",\n\t\tRoot:     \"/\",\n\t\tRelative: \"c/d\",\n\t\tGOOS:     runtime.DARWIN,\n\t\tExpected: Folders{\n\t\t\t{Name: \"c\", Path: \"/c\"},\n\t\t\t{Name: \"d\", Path: \"/c/d\"},\n\t\t},\n\t},\n\t{\n\t\tCase:         \"Home directory - git folder\",\n\t\tRoot:         \"~\",\n\t\tRelative:     \"c/d\",\n\t\tGOOS:         runtime.DARWIN,\n\t\tGitDir:       &runtime.FileInfo{IsDir: true, ParentFolder: \"/a/b/c\"},\n\t\tGitDirFormat: \"<b>%s</b>\",\n\t\tExpected: Folders{\n\t\t\t{Name: \"<b>c</b>\", Path: \"~/c\", Display: true},\n\t\t\t{Name: \"d\", Path: \"~/c/d\"},\n\t\t},\n\t},\n}\n\nvar testNormalizePathCases = []testNormalizePathCase{\n\t{\n\t\tCase:     \"Linux: home prefix, backslash included\",\n\t\tInput:    \"~/Bob\\\\Foo\",\n\t\tHomeDir:  homeDir,\n\t\tGOOS:     runtime.LINUX,\n\t\tExpected: homeDir + \"/Bob\\\\Foo\",\n\t},\n\t{\n\t\tCase:     \"macOS: home prefix, backslash included\",\n\t\tInput:    \"~/Bob\\\\Foo\",\n\t\tHomeDir:  homeDir,\n\t\tGOOS:     runtime.DARWIN,\n\t\tExpected: homeDir + \"/bob\\\\foo\",\n\t},\n\t{\n\t\tCase:     \"Linux: absolute\",\n\t\tInput:    \"/foo/~/bar\",\n\t\tHomeDir:  homeDir,\n\t\tGOOS:     runtime.LINUX,\n\t\tExpected: \"/foo/~/bar\",\n\t},\n\t{\n\t\tCase:     \"Linux: home prefix\",\n\t\tInput:    \"~/baz\",\n\t\tHomeDir:  homeDir,\n\t\tGOOS:     runtime.LINUX,\n\t\tExpected: homeDir + \"/baz\",\n\t},\n}\n\nfunc TestFolderPathCustomMappedLocations(t *testing.T) {\n\tpwd := abcd\n\tenv := new(mock.Environment)\n\tenv.On(\"PathSeparator\").Return(\"/\")\n\tenv.On(\"Home\").Return(homeDir)\n\tenv.On(\"Pwd\").Return(pwd)\n\tenv.On(\"GOOS\").Return(\"\")\n\targs := &runtime.Flags{\n\t\tPSWD: pwd,\n\t}\n\tenv.On(\"Flags\").Return(args)\n\tenv.On(\"Shell\").Return(shell.GENERIC)\n\n\ttemplate.Cache = new(cache.Template)\n\ttemplate.Init(env, nil, nil)\n\n\tprops := options.Map{\n\t\toptions.Style: FolderType,\n\t\tMappedLocations: map[string]string{\n\t\t\tabcd: \"#\",\n\t\t},\n\t}\n\n\tpath := &Path{}\n\tpath.Init(props, env)\n\n\tpath.setPaths()\n\tpath.setStyle()\n\n\tgot := renderTemplateNoTrimSpace(env, \"{{ .Path }}\", path)\n\tassert.Equal(t, \"#\", got)\n}\n\nfunc TestReplaceMappedLocations(t *testing.T) {\n\tcases := []struct {\n\t\tCase                   string\n\t\tPwd                    string\n\t\tExpected               string\n\t\tMappedLocationsEnabled bool\n\t}{\n\t\t{Pwd: \"/c/l/k/f\", Expected: \"f\"},\n\t\t{Pwd: \"/f/g/h\", Expected: \"/f/g/h\"},\n\t\t{Pwd: \"/f/g/h/e\", Expected: \"^/e\"},\n\t\t{Pwd: abcd, Expected: \"#\"},\n\t\t{Pwd: \"/a/b/c/d/e\", Expected: \"#/e\"},\n\t\t{Pwd: \"/a/b/c/D/e\", Expected: \"#/e\"},\n\t\t{Pwd: \"/a/b/k/j/e\", Expected: \"e\"},\n\t\t{Pwd: \"/a/b/k/l\", Expected: \"@/l\"},\n\t\t{Pwd: \"/a/b/k/l\", MappedLocationsEnabled: true, Expected: \"~/l\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"Shell\").Return(shell.FISH)\n\t\tenv.On(\"GOOS\").Return(runtime.DARWIN)\n\t\tenv.On(\"Home\").Return(\"/a/b/k\")\n\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tprops := options.Map{\n\t\t\tMappedLocationsEnabled: tc.MappedLocationsEnabled,\n\t\t\tMappedLocations: map[string]string{\n\t\t\t\tabcd:       \"#\",\n\t\t\t\t\"/f/g/h/*\": \"^\",\n\t\t\t\t\"/c/l/k/*\": \"\",\n\t\t\t\t\"~\":        \"@\",\n\t\t\t\t\"~/j/*\":    \"\",\n\t\t\t},\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tassert.Equal(t, tc.Expected, path.pwd)\n\t}\n}\n\nfunc TestGetPwd(t *testing.T) {\n\tcases := []struct {\n\t\tPwd                    string\n\t\tPswd                   string\n\t\tExpected               string\n\t\tMappedLocationsEnabled bool\n\t}{\n\t\t{MappedLocationsEnabled: true, Pwd: homeDir, Expected: \"~\"},\n\t\t{MappedLocationsEnabled: true, Pwd: homeDir + \"-test\", Expected: homeDir + \"-test\"},\n\t\t{MappedLocationsEnabled: true},\n\t\t{MappedLocationsEnabled: true, Pwd: \"/usr\", Expected: \"/usr\"},\n\t\t{MappedLocationsEnabled: true, Pwd: homeDir + abc, Expected: \"~/abc\"},\n\t\t{MappedLocationsEnabled: true, Pwd: abcd, Expected: \"#\"},\n\t\t{MappedLocationsEnabled: true, Pwd: \"/a/b/c/d/e/f/g\", Expected: \"#/e/f/g\"},\n\t\t{MappedLocationsEnabled: true, Pwd: \"/z/y/x/w\", Expected: \"/z/y/x/w\"},\n\n\t\t{MappedLocationsEnabled: false},\n\t\t{MappedLocationsEnabled: false, Pwd: homeDir + abc, Expected: homeDir + abc},\n\t\t{MappedLocationsEnabled: false, Pwd: \"/a/b/c/d/e/f/g\", Expected: \"#/e/f/g\"},\n\t\t{MappedLocationsEnabled: false, Pwd: homeDir + cdefg, Expected: homeDir + cdefg},\n\t\t{MappedLocationsEnabled: true, Pwd: homeDir + cdefg, Expected: \"~/c/d/e/f/g\"},\n\n\t\t{MappedLocationsEnabled: true, Pwd: \"/w/d/x/w\", Pswd: \"/z/y/x/w\", Expected: \"/z/y/x/w\"},\n\t\t{MappedLocationsEnabled: false, Pwd: \"/f/g/k/d/e/f/g\", Pswd: \"/a/b/c/d/e/f/g\", Expected: \"#/e/f/g\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Home\").Return(homeDir)\n\t\tenv.On(\"Pwd\").Return(tc.Pwd)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\targs := &runtime.Flags{\n\t\t\tPSWD: tc.Pswd,\n\t\t}\n\t\tenv.On(\"Flags\").Return(args)\n\t\tenv.On(\"Shell\").Return(shell.PWSH)\n\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tprops := options.Map{\n\t\t\tMappedLocationsEnabled: tc.MappedLocationsEnabled,\n\t\t\tMappedLocations: map[string]string{\n\t\t\t\tabcd: \"#\",\n\t\t\t},\n\t\t}\n\n\t\tpath := &Path{}\n\t\tpath.Init(props, env)\n\n\t\tpath.setPaths()\n\t\tassert.Equal(t, tc.Expected, path.pwd)\n\t}\n}\n"
  },
  {
    "path": "src/segments/path_windows_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n)\n\nconst (\n\tfooBarMan = \"\\\\foo\\\\bar\\\\man\"\n)\n\nvar testParentCases = []testParentCase{\n\t{\n\t\tCase:          \"Windows Home folder\",\n\t\tHomePath:      homeDirWindows,\n\t\tPwd:           homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows drive root\",\n\t\tHomePath:      homeDirWindows,\n\t\tPwd:           \"C:\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows drive root with a trailing separator\",\n\t\tHomePath:      homeDirWindows,\n\t\tPwd:           \"C:\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows drive root + 1\",\n\t\tExpected:      \"C:\\\\\",\n\t\tHomePath:      homeDirWindows,\n\t\tPwd:           \"C:\\\\test\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"PSDrive root\",\n\t\tHomePath:      homeDirWindows,\n\t\tPwd:           \"HKLM:\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n}\n\nvar testAgnosterPathStyleCases = []testAgnosterPathStyleCase{\n\t{\n\t\tStyle:               Unique,\n\t\tExpected:            \"C > a > ab > abcd\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\ab\\\\ab\\\\abcd\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"C: > \",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"C > s > .w > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\something\\\\.whatever\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Letter,\n\t\tExpected:            \"~ > s > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + \"\\\\something\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"C: > .. > foo > .. > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\Users\\\\foo\\\\foobar\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"c > .. > foo > .. > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\Users\\\\foo\\\\foobar\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tShell:               shell.BASH,\n\t\tCygwin:              true,\n\t\tCygpath:             \"/c/Users/foo/foobar/man\",\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               Mixed,\n\t\tExpected:            \"C: > .. > foo > .. > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\Users\\\\foo\\\\foobar\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tShell:               shell.BASH,\n\t\tCygpathError:        errors.New(\"oh no\"),\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"\\\\\\\\localhost\\\\c$ > some\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"\\\\\\\\localhost\\\\c$\\\\some\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"\\\\\\\\localhost\\\\c$\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"\\\\\\\\localhost\\\\c$\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. > bar > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + fooBarMan,\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"C: > \",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"C: > .. > bar > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\usr\\\\foo\\\\bar\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"C: > .. > foo > bar > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 \"C:\\\\usr\\\\foo\\\\bar\\\\man\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > .. > bar > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + fooBarMan,\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > foo > bar > man\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + fooBarMan,\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            3,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows,\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            1,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \".. > foo\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + \"\\\\foo\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            1,\n\t\tHideRootLocation:    true,\n\t},\n\t{\n\t\tStyle:               AgnosterShort,\n\t\tExpected:            \"~ > foo\",\n\t\tHomePath:            homeDirWindows,\n\t\tPwd:                 homeDirWindows + \"\\\\foo\",\n\t\tGOOS:                runtime.WINDOWS,\n\t\tPathSeparator:       `\\`,\n\t\tFolderSeparatorIcon: \" > \",\n\t\tMaxDepth:            2,\n\t\tHideRootLocation:    true,\n\t},\n}\n\nvar testAgnosterPathCases = []testAgnosterPathCase{\n\t{\n\t\tCase:          \"Windows registry drive case sensitive\",\n\t\tExpected:      \"\\uf013 > f > magnetic:TOAST\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"HKLM:\\\\SOFTWARE\\\\magnetic:TOAST\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows outside home\",\n\t\tExpected:      \"C: > f > f > location\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Program Files\\\\Go\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows outside home\",\n\t\tExpected:      \"~ > f > f > location\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           homeDirWindows + \"\\\\Documents\\\\Bill\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows inside home zero levels\",\n\t\tExpected:      \"C: > location\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows inside home one level\",\n\t\tExpected:      \"C: > f > location\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Program Files\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower case drive letter\",\n\t\tExpected:      \"C: > Windows\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Windows\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower case drive letter (other)\",\n\t\tExpected:      \"P: > Other\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"P:\\\\Other\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive\",\n\t\tExpected:      \"some: > some\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"some:\\\\some\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive (ending with c)\",\n\t\tExpected:      \"src: > source\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"src:\\\\source\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive (arbitrary cases)\",\n\t\tExpected:      \"sRc: > source\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"sRc:\\\\source\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows registry drive\",\n\t\tExpected:      \"\\uf013 > f > magnetic:test\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"HKLM:\\\\SOFTWARE\\\\magnetic:test\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n}\n\nvar testAgnosterLeftPathCases = []testAgnosterLeftPathCase{\n\t{\n\t\tCase:          \"Windows inside home\",\n\t\tExpected:      \"~ > Documents > f > f\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           homeDirWindows + \"\\\\Documents\\\\Bill\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows outside home\",\n\t\tExpected:      \"C: > Program Files > f > f\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Program Files\\\\Go\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows inside home zero levels\",\n\t\tExpected:      \"C: > location\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows inside home one level\",\n\t\tExpected:      \"C: > Program Files > f\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Program Files\\\\location\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower case drive letter\",\n\t\tExpected:      \"C: > Windows\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"C:\\\\Windows\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower case drive letter (other)\",\n\t\tExpected:      \"P: > Other\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"P:\\\\Other\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive\",\n\t\tExpected:      \"some: > some\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"some:\\\\some\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive (ending with c)\",\n\t\tExpected:      \"src: > source\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"src:\\\\source\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows lower word drive (arbitrary cases)\",\n\t\tExpected:      \"sRc: > source\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"sRc:\\\\source\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows registry drive\",\n\t\tExpected:      \"\\uf013 > SOFTWARE > f\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"HKLM:\\\\SOFTWARE\\\\magnetic:test\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n\t{\n\t\tCase:          \"Windows registry drive case sensitive\",\n\t\tExpected:      \"\\uf013 > SOFTWARE > f\",\n\t\tHome:          homeDirWindows,\n\t\tPWD:           \"HKLM:\\\\SOFTWARE\\\\magnetic:TOAST\\\\\",\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t},\n}\n\nvar testFullAndFolderPathCases = []testFullAndFolderPathCase{\n\t{Style: FolderType, FolderSeparatorIcon: `\\`, Pwd: \"C:\\\\\", Expected: \"C:\\\\\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n\t{Style: FolderType, FolderSeparatorIcon: `\\`, Pwd: \"\\\\\\\\localhost\\\\d$\", Expected: \"\\\\\\\\localhost\\\\d$\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n\t{Style: FolderType, FolderSeparatorIcon: `\\`, Pwd: homeDirWindows, Expected: \"~\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n\t{Style: Full, FolderSeparatorIcon: `\\`, Pwd: homeDirWindows, Expected: \"~\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n\t{Style: Full, FolderSeparatorIcon: `\\`, Pwd: homeDirWindows + \"\\\\abc\", Expected: \"~\\\\abc\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n\t{Style: Full, FolderSeparatorIcon: `\\`, Pwd: \"C:\\\\Users\\\\posh\", Expected: \"C:\\\\Users\\\\posh\", PathSeparator: `\\`, GOOS: runtime.WINDOWS},\n}\n\nvar testFullPathCustomMappedLocationsCases = []testFullPathCustomMappedLocationsCase{\n\t{\n\t\tPwd:             `\\a\\b\\c\\d`,\n\t\tMappedLocations: map[string]string{`\\a\\b`: \"#\"},\n\t\tGOOS:            runtime.WINDOWS,\n\t\tPathSeparator:   `\\`,\n\t\tExpected:        `#\\c\\d`,\n\t},\n\t{\n\t\tPwd:             `\\a\\b\\1234\\d\\e`,\n\t\tMappedLocations: map[string]string{`re:(/a/b/[0-9]+/d).*`: \"#\"},\n\t\tGOOS:            runtime.WINDOWS,\n\t\tPathSeparator:   `\\`,\n\t\tExpected:        `#\\e`,\n\t},\n\t{\n\t\tPwd:             `\\a\\b\\1234\\f\\e`,\n\t\tMappedLocations: map[string]string{`re:(/a/b/[0-9]+/d).*`: \"#\"},\n\t\tGOOS:            runtime.WINDOWS,\n\t\tPathSeparator:   `\\`,\n\t\tExpected:        `\\a\\b\\1234\\f\\e`,\n\t},\n\t{\n\t\tPwd:             `C:\\Users\\taylo\\Documents\\github\\project`,\n\t\tMappedLocations: map[string]string{`re:(.*Users/taylo/Documents/GitHub).*`: \"github\"},\n\t\tGOOS:            runtime.WINDOWS,\n\t\tPathSeparator:   `\\`,\n\t\tExpected:        `github\\project`,\n\t},\n}\n\nvar testSplitPathCases = []testSplitPathCase{\n\t{\n\t\tCase:         \"Home directory - git folder on Windows\",\n\t\tRoot:         \"C:\",\n\t\tRelative:     \"a/b/c/d\",\n\t\tGOOS:         runtime.WINDOWS,\n\t\tGitDir:       &runtime.FileInfo{IsDir: true, ParentFolder: \"C:/a/b/c\"},\n\t\tGitDirFormat: \"<b>%s</b>\",\n\t\tExpected: Folders{\n\t\t\t{Name: \"a\", Path: \"C:/a\"},\n\t\t\t{Name: \"b\", Path: \"C:/a/b\"},\n\t\t\t{Name: \"<b>c</b>\", Path: \"C:/a/b/c\", Display: true},\n\t\t\t{Name: \"d\", Path: \"C:/a/b/c/d\"},\n\t\t},\n\t},\n}\n\nvar testNormalizePathCases = []testNormalizePathCase{\n\t{\n\t\tCase:          \"Windows: absolute w/o drive letter, forward slash included\",\n\t\tInput:         \"/foo/~/bar\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\foo\\\\~\\\\bar\",\n\t},\n\t{\n\t\tCase:          \"Windows: absolute\",\n\t\tInput:         homeDirWindows + \"\\\\Foo\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"c:\\\\users\\\\someone\\\\foo\",\n\t},\n\t{\n\t\tCase:          \"Windows: home prefix\",\n\t\tInput:         \"~\\\\Bob\\\\Foo\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"c:\\\\users\\\\someone\\\\bob\\\\foo\",\n\t},\n\t{\n\t\tCase:          \"Windows: home prefix\",\n\t\tInput:         \"~/baz\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"c:\\\\users\\\\someone\\\\baz\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC root w/ prefix\",\n\t\tInput:         `\\\\.\\UNC\\localhost\\c$`,\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC root w/ prefix, forward slash included\",\n\t\tInput:         \"//./UNC/localhost/c$\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC root\",\n\t\tInput:         `\\\\localhost\\c$\\`,\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC root, forward slash included\",\n\t\tInput:         \"//localhost/c$\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC\",\n\t\tInput:         `\\\\localhost\\c$\\some`,\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\\\\some\",\n\t},\n\t{\n\t\tCase:          \"Windows: UNC, forward slash included\",\n\t\tInput:         \"//localhost/c$/some\",\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"\\\\\\\\localhost\\\\c$\\\\some\",\n\t},\n\t{\n\t\tCase:          \"Windows: display Cygwin path\",\n\t\tInput:         fooBarMan,\n\t\tHomeDir:       homeDirWindows,\n\t\tGOOS:          runtime.WINDOWS,\n\t\tPathSeparator: `\\`,\n\t\tExpected:      \"/foo/bar/man\",\n\t\tCygwin:        true,\n\t},\n}\n"
  },
  {
    "path": "src/segments/perl.go",
    "content": "package segments\n\ntype Perl struct {\n\tLanguage\n}\n\nfunc (p *Perl) Template() string {\n\treturn languageTemplate\n}\n\nfunc (p *Perl) Enabled() bool {\n\tperlRegex := `This is perl.*v(?P<version>(?P<major>[0-9]+)(?:\\.(?P<minor>[0-9]+))(?:\\.(?P<patch>[0-9]+))?).* built for .+`\n\tp.extensions = []string{\n\t\t\".perl-version\",\n\t\t\"*.pl\",\n\t\t\"*.pm\",\n\t\t\"*.t\",\n\t}\n\tp.tooling = map[string]*cmd{\n\t\t\"perl\": {\n\t\t\texecutable: \"perl\",\n\t\t\targs:       []string{\"-version\"},\n\t\t\tregex:      perlRegex,\n\t\t},\n\t}\n\tp.defaultTooling = []string{\"perl\"}\n\n\treturn p.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/perl_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPerl(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tVersion         string\n\t\tPerlHomeVersion string\n\t\tPerlHomeEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:           \"v5.12+\",\n\t\t\tExpectedString: \"5.32.1\",\n\t\t\tVersion:        \"This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"v5.6 - v5.10\",\n\t\t\tExpectedString: \"5.6.1\",\n\t\t\tVersion:        \"This is perl, v5.6.1 built for MSWin32-x86-multi-thread\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"perl\",\n\t\t\tversionParam:  \"-version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \".perl-version\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tp := &Perl{}\n\t\tp.Init(props, env)\n\t\tassert.True(t, p.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, p.Template(), p), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/php.go",
    "content": "package segments\n\ntype Php struct {\n\tLanguage\n}\n\nfunc (p *Php) Template() string {\n\treturn languageTemplate\n}\n\nfunc (p *Php) Enabled() bool {\n\tp.extensions = []string{\"*.php\", \"composer.json\", \"composer.lock\", \".php-version\", \"blade.php\"}\n\tp.tooling = map[string]*cmd{\n\t\t\"php\": {\n\t\t\texecutable: \"php\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:PHP (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tp.defaultTooling = []string{\"php\"}\n\tp.versionURLTemplate = \"https://www.php.net/ChangeLog-{{ .Major }}.php#PHP_{{ .Major }}_{{ .Minor }}\"\n\n\treturn p.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/php_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPhp(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"PHP 6.1.0\", ExpectedString: \"6.1.0\", Version: \"PHP 6.1.0(cli) (built: Jul  2 2021 03:59:48) ( NTS )\"},\n\t\t{Case: \"php 7.4.21\", ExpectedString: \"7.4.21\", Version: \"PHP 7.4.21 (cli) (built: Jul  2 2021 03:59:48) ( NTS )\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"php\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.php\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tj := &Php{}\n\t\tj.Init(props, env)\n\t\tassert.True(t, j.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, j.Template(), j), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/plastic.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype PlasticStatus struct {\n\tScmStatus\n}\n\nfunc (s *PlasticStatus) add(code string) {\n\tswitch code {\n\tcase \"LD\":\n\t\ts.Deleted++\n\tcase \"AD\", \"PR\":\n\t\ts.Added++\n\tcase \"LM\":\n\t\ts.Moved++\n\tcase \"CH\", \"CO\":\n\t\ts.Modified++\n\t}\n}\n\ntype Plastic struct {\n\tStatus                 *PlasticStatus\n\tSelector               string\n\tplasticWorkspaceFolder string\n\tScm\n\tBehind       bool\n\tMergePending bool\n}\n\nfunc (p *Plastic) Init(props options.Provider, env runtime.Environment) {\n\tp.options = props\n\tp.env = env\n}\n\nfunc (p *Plastic) Template() string {\n\treturn \" {{ .Selector }} \"\n}\n\nfunc (p *Plastic) Enabled() bool {\n\tif !p.env.HasCommand(\"cm\") {\n\t\treturn false\n\t}\n\n\twkdir, err := p.env.HasParentFilePath(\".plastic\", false)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tif !wkdir.IsDir {\n\t\treturn false\n\t}\n\n\tp.plasticWorkspaceFolder = wkdir.ParentFolder\n\tdisplayStatus := p.options.Bool(FetchStatus, false)\n\tp.setSelector()\n\tif displayStatus {\n\t\tp.setPlasticStatus()\n\t}\n\treturn true\n}\n\nfunc (p *Plastic) CacheKey() (string, bool) {\n\tdir, err := p.env.HasParentFilePath(\".plastic\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn dir.Path, true\n}\n\nfunc (p *Plastic) setPlasticStatus() {\n\toutput := p.getCmCommandOutput(\"status\", \"--all\", \"--machinereadable\")\n\tsplittedOutput := strings.Split(output, \"\\n\")\n\t// compare to head\n\tcurrentChangeset := p.parseStatusChangeset(splittedOutput[0])\n\theadChangeset := p.getHeadChangeset()\n\tp.Behind = headChangeset > currentChangeset\n\n\tstatusFormats := p.options.KeyValueMap(StatusFormats, map[string]string{})\n\tp.Status = &PlasticStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\t// parse file state\n\tp.MergePending = false\n\tp.parseFilesStatus(splittedOutput)\n}\n\nfunc (p *Plastic) parseFilesStatus(output []string) {\n\tif len(output) <= 1 {\n\t\treturn\n\t}\n\tfor _, line := range output[1:] {\n\t\tif len(line) < 3 {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(line, \"NO_MERGES\") {\n\t\t\tp.Status.Unmerged++\n\t\t\tcontinue\n\t\t}\n\n\t\tp.MergePending = p.MergePending || regex.MatchString(`(?i)\\smerge\\s+from\\s+[0-9]+\\s*$`, line)\n\n\t\tcode := line[:2]\n\t\tp.Status.add(code)\n\t}\n}\n\nfunc (p *Plastic) parseStringPattern(output, pattern, name string) string {\n\tmatch := regex.FindNamedRegexMatch(pattern, output)\n\tif sValue, ok := match[name]; ok {\n\t\treturn sValue\n\t}\n\treturn \"\"\n}\n\nfunc (p *Plastic) parseIntPattern(output, pattern, name string, defValue int) int {\n\tsValue := p.parseStringPattern(output, pattern, name)\n\tif len(sValue) > 0 {\n\t\tiValue, _ := strconv.Atoi(sValue)\n\t\treturn iValue\n\t}\n\treturn defValue\n}\n\nfunc (p *Plastic) parseStatusChangeset(status string) int {\n\treturn p.parseIntPattern(status, `STATUS\\s+(?P<cs>[0-9]+?)\\s`, \"cs\", 0)\n}\n\nfunc (p *Plastic) getHeadChangeset() int {\n\toutput := p.getCmCommandOutput(\"status\", \"--head\", \"--machinereadable\")\n\treturn p.parseIntPattern(output, `\\bcs:(?P<cs>[0-9]+?)\\s`, \"cs\", 0)\n}\n\nfunc (p *Plastic) setSelector() {\n\tvar ref string\n\tselector := p.fileContent(p.plasticWorkspaceFolder+\"/.plastic/\", \"plastic.selector\")\n\n\t// changeset\n\tref = p.parseChangesetSelector(selector)\n\tif len(ref) > 0 {\n\t\tp.Selector = fmt.Sprintf(\"%s%s\", p.options.String(CommitIcon, \"\\uF417\"), ref)\n\t\treturn\n\t}\n\n\t// fallback to label\n\tref = p.parseLabelSelector(selector)\n\tif len(ref) > 0 {\n\t\tp.Selector = fmt.Sprintf(\"%s%s\", p.options.String(TagIcon, \"\\uF412\"), ref)\n\t\treturn\n\t}\n\n\t// fallback to branch/smartbranch\n\tref = p.parseBranchSelector(selector)\n\tif len(ref) > 0 {\n\t\tref = p.formatBranch(ref)\n\t}\n\n\tp.Selector = fmt.Sprintf(\"%s%s\", p.options.String(BranchIcon, \"\\uE0A0\"), ref)\n}\n\nfunc (p *Plastic) parseChangesetSelector(selector string) string {\n\treturn p.parseStringPattern(selector, `\\bchangeset \"(?P<cs>[0-9]+?)\"`, \"cs\")\n}\n\nfunc (p *Plastic) parseLabelSelector(selector string) string {\n\treturn p.parseStringPattern(selector, `label \"(?P<label>[a-zA-Z0-9\\-\\_]+?)\"`, \"label\")\n}\n\nfunc (p *Plastic) parseBranchSelector(selector string) string {\n\treturn p.parseStringPattern(selector, `branch \"(?P<branch>[\\/a-zA-Z0-9\\-\\_]+?)\"`, \"branch\")\n}\n\nfunc (p *Plastic) getCmCommandOutput(args ...string) string {\n\tval, _ := p.env.RunCommand(\"cm\", args...)\n\treturn val\n}\n"
  },
  {
    "path": "src/segments/plastic_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPlasticEnabledNotFound(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"HasCommand\", \"cm\").Return(false)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\n\tp := &Plastic{}\n\tp.Init(options.Map{}, env)\n\n\tassert.False(t, p.Enabled())\n}\n\nfunc TestPlasticEnabledInWorkspaceDirectory(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"HasCommand\", \"cm\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"FileContent\", \"/dir/.plastic//plastic.selector\").Return(\"\")\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/hello\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv.On(\"HasParentFilePath\", \".plastic\", false).Return(fileInfo, nil)\n\n\tp := &Plastic{}\n\tp.Init(options.Map{}, env)\n\n\tassert.True(t, p.Enabled())\n\tassert.Equal(t, fileInfo.ParentFolder, p.plasticWorkspaceFolder)\n}\n\nfunc setupCmStatusEnv(status, headStatus string) *Plastic {\n\tenv := new(mock.Environment)\n\tenv.On(\"RunCommand\", \"cm\", []string{\"status\", \"--all\", \"--machinereadable\"}).Return(status, nil)\n\tenv.On(\"RunCommand\", \"cm\", []string{\"status\", \"--head\", \"--machinereadable\"}).Return(headStatus, nil)\n\n\tp := &Plastic{}\n\tp.Init(options.Map{}, env)\n\n\treturn p\n}\n\nfunc TestPlasticGetCmOutputForCommand(t *testing.T) {\n\twant := \"je suis le output\"\n\tp := setupCmStatusEnv(want, \"\")\n\tgot := p.getCmCommandOutput(\"status\", \"--all\", \"--machinereadable\")\n\tassert.Equal(t, want, got)\n}\n\nfunc TestPlasticStatusBehind(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tStatus   string\n\t\tHead     string\n\t\tExpected bool\n\t}{\n\t\t{\n\t\t\tCase:     \"Not behind\",\n\t\t\tExpected: false,\n\t\t\tStatus:   \"STATUS 20 default localhost:8087\",\n\t\t\tHead:     \"STATUS cs:20 rep:default repserver:localhost:8087\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Behind\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 2 default localhost:8087\",\n\t\t\tHead:     \"STATUS cs:20 rep:default repserver:localhost:8087\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tp := setupCmStatusEnv(tc.Status, tc.Head)\n\t\tp.setPlasticStatus()\n\t\tassert.Equal(t, tc.Expected, p.Behind, tc.Case)\n\t}\n}\n\nfunc TestPlasticStatusChanged(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tStatus   string\n\t\tExpected bool\n\t}{\n\t\t{\n\t\t\tCase:     \"No changes\",\n\t\t\tExpected: false,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Changed file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nCH /some.file\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Added file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nAD /some.file\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Added (pivate) file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nPR /some.file\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Moved file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nLM /some.file\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Deleted file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nLD /some.file\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Unmerged file\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nCO /some.file NO_MERGES\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tp := setupCmStatusEnv(tc.Status, \"\")\n\t\tp.setPlasticStatus()\n\t\tassert.Equal(t, tc.Expected, p.Status.Changed(), tc.Case)\n\t}\n}\n\nfunc TestPlasticStatusCounts(t *testing.T) {\n\tstatus := \"STATUS 1 default localhost:8087\" +\n\t\t\"\\r\\nCO /some.file NO_MERGES\" +\n\t\t\"\\r\\nAD /some.file\" +\n\t\t\"\\r\\nCH /some.file\\r\\nCH /some.file\" +\n\t\t\"\\r\\nLD /some.file\\r\\nLD /some.file\\r\\nLD /some.file\" +\n\t\t\"\\r\\nLM /some.file\\r\\nLM /some.file\\r\\nLM /some.file\\r\\nLM /some.file\"\n\tp := setupCmStatusEnv(status, \"\")\n\tp.setPlasticStatus()\n\ts := p.Status\n\tassert.Equal(t, 1, s.Unmerged)\n\tassert.Equal(t, 1, s.Added)\n\tassert.Equal(t, 2, s.Modified)\n\tassert.Equal(t, 3, s.Deleted)\n\tassert.Equal(t, 4, s.Moved)\n}\n\nfunc TestPlasticMergePending(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tStatus   string\n\t\tExpected bool\n\t}{\n\t\t{\n\t\t\tCase:     \"No pending merge\",\n\t\t\tExpected: false,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Pending merge\",\n\t\t\tExpected: true,\n\t\t\tStatus:   \"STATUS 1 default localhost:8087\\r\\nCH /some.file merge from 8\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tp := setupCmStatusEnv(tc.Status, \"\")\n\t\tp.setPlasticStatus()\n\t\tassert.Equal(t, tc.Expected, p.MergePending, tc.Case)\n\t}\n}\n\nfunc TestPlasticParseIntPattern(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tText     string\n\t\tPattern  string\n\t\tName     string\n\t\tExpected int\n\t\tDefault  int\n\t}{\n\t\t{\n\t\t\tCase:     \"int found\",\n\t\t\tExpected: 123,\n\t\t\tText:     \"Some number 123 in text\",\n\t\t\tPattern:  `\\s(?P<x>[0-9]+?)\\s`,\n\t\t\tName:     \"x\",\n\t\t\tDefault:  0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"int not found\",\n\t\t\tExpected: 0,\n\t\t\tText:     \"No number in text\",\n\t\t\tPattern:  `\\s(?P<x>[0-9]+?)\\s`,\n\t\t\tName:     \"x\",\n\t\t\tDefault:  0,\n\t\t},\n\t\t{\n\t\t\tCase:     \"empty text\",\n\t\t\tExpected: 0,\n\t\t\tText:     \"\",\n\t\t\tPattern:  `\\s(?P<x>[0-9]+?)\\s`,\n\t\t\tName:     \"x\",\n\t\t\tDefault:  0,\n\t\t},\n\t}\n\n\tp := &Plastic{}\n\tfor _, tc := range cases {\n\t\tvalue := p.parseIntPattern(tc.Text, tc.Pattern, tc.Name, tc.Default)\n\t\tassert.Equal(t, tc.Expected, value, tc.Case)\n\t}\n}\n\nfunc TestPlasticParseStatusChangeset(t *testing.T) {\n\tp := &Plastic{}\n\tcs := p.parseStatusChangeset(\"STATUS 321 default localhost:8087\")\n\tassert.Equal(t, 321, cs)\n}\n\nfunc TestPlasticGetHeadChangeset(t *testing.T) {\n\thead := \"STATUS cs:321 rep:default repserver:localhost:8087\"\n\tp := setupCmStatusEnv(\"\", head)\n\tcs := p.getHeadChangeset()\n\tassert.Equal(t, 321, cs)\n}\n\nfunc TestPlasticParseChangesetSelector(t *testing.T) {\n\tcontent := \"repository \\\"default\\\"\\r\\n\tpath \\\"/\\\"\\r\\n\t  smartbranch \\\"/main\\\" changeset \\\"321\\\"\"\n\tp := &Plastic{}\n\tselector := p.parseChangesetSelector(content)\n\tassert.Equal(t, \"321\", selector)\n}\n\nfunc TestPlasticParseLabelSelector(t *testing.T) {\n\tcontent := \"repository \\\"default\\\"\\r\\n\tpath \\\"/\\\"\\r\\n\t  label \\\"BL003\\\"\"\n\tp := &Plastic{}\n\tselector := p.parseLabelSelector(content)\n\tassert.Equal(t, \"BL003\", selector)\n}\n\nfunc TestPlasticParseBranchSelector(t *testing.T) {\n\tcontent := \"repository \\\"default\\\"\\r\\n\tpath \\\"/\\\"\\r\\n\t  branch \\\"/main/fix-004\\\"\"\n\tp := &Plastic{}\n\tselector := p.parseBranchSelector(content)\n\tassert.Equal(t, \"/main/fix-004\", selector)\n}\n\nfunc TestPlasticParseSmartbranchSelector(t *testing.T) {\n\tcontent := \"repository \\\"default\\\"\\r\\n\tpath \\\"/\\\"\\r\\n\t  smartbranch \\\"/main/fix-002\\\"\"\n\tp := &Plastic{}\n\tselector := p.parseBranchSelector(content)\n\tassert.Equal(t, \"/main/fix-002\", selector)\n}\n\nfunc TestPlasticStatus(t *testing.T) {\n\tp := &Plastic{\n\t\tStatus: &PlasticStatus{\n\t\t\tScmStatus: ScmStatus{\n\t\t\t\tAdded:    1,\n\t\t\t\tModified: 2,\n\t\t\t\tDeleted:  3,\n\t\t\t\tMoved:    4,\n\t\t\t\tUnmerged: 5,\n\t\t\t},\n\t\t},\n\t}\n\tstatus := p.Status.String()\n\texpected := \"+1 ~2 -3 >4 x5\"\n\tassert.Equal(t, expected, status)\n}\n\nfunc TestPlasticTemplateString(t *testing.T) {\n\tcases := []struct {\n\t\tPlastic  *Plastic\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{\n\t\t\tCase:     \"Default template\",\n\t\t\tExpected: \"/main\",\n\t\t\tTemplate: \"{{ .Selector }}\",\n\t\t\tPlastic: &Plastic{\n\t\t\t\tSelector: \"/main\",\n\t\t\t\tBehind:   false,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Workspace changes\",\n\t\t\tExpected: \"/main \\uF044 +2 ~3 -1 >4\",\n\t\t\tTemplate: \"{{ .Selector }}{{ if .Status.Changed }} \\uF044 {{ .Status.String }}{{ end }}\",\n\t\t\tPlastic: &Plastic{\n\t\t\t\tSelector: \"/main\",\n\t\t\t\tStatus: &PlasticStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t\tDeleted:  1,\n\t\t\t\t\t\tMoved:    4,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No workspace changes\",\n\t\t\tExpected: \"/main\",\n\t\t\tTemplate: \"{{ .Selector }}{{ if .Status.Changed }} \\uF044 {{ .Status.String }}{{ end }}\",\n\t\t\tPlastic: &Plastic{\n\t\t\t\tSelector: \"/main\",\n\t\t\t\tStatus:   &PlasticStatus{},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\t\ttc.Plastic.options = props\n\t\tenv := new(mock.Environment)\n\t\ttc.Plastic.env = env\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Plastic), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/pnpm.go",
    "content": "package segments\n\ntype Pnpm struct {\n\tLanguage\n}\n\nfunc (n *Pnpm) Enabled() bool {\n\tn.extensions = []string{\"package.json\", \"pnpm-lock.yaml\"}\n\tn.tooling = map[string]*cmd{\n\t\t\"pnpm\": {\n\t\t\texecutable: \"pnpm\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tn.defaultTooling = []string{\"pnpm\"}\n\tn.versionURLTemplate = \"https://github.com/pnpm/pnpm/releases/tag/v{{ .Full }}\"\n\n\treturn n.Language.Enabled()\n}\n\nfunc (n *Pnpm) Template() string {\n\treturn \" \\ue865 {{.Full}} \"\n}\n"
  },
  {
    "path": "src/segments/pnpm_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestPnpm(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"1.0.0\", ExpectedString: \"\\ue865 1.0.0\", Version: \"1.0.0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"pnpm\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"package.json\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tpnpm := &Pnpm{}\n\t\tpnpm.Init(props, env)\n\t\tassert.True(t, pnpm.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, pnpm.Template(), pnpm), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/posh_git.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nconst (\n\tposhGitEnv = \"POSH_GIT_STATUS\"\n)\n\ntype poshGit struct {\n\tIndex        *poshGitStatus `json:\"Index\"`\n\tWorking      *poshGitStatus `json:\"Working\"`\n\tRepoName     string         `json:\"RepoName\"`\n\tBranch       string         `json:\"Branch\"`\n\tGitDir       string         `json:\"GitDir\"`\n\tUpstream     string         `json:\"Upstream\"`\n\tStashCount   int            `json:\"StashCount\"`\n\tAheadBy      int            `json:\"AheadBy\"`\n\tBehindBy     int            `json:\"BehindBy\"`\n\tHasWorking   bool           `json:\"HasWorking\"`\n\tHasIndex     bool           `json:\"HasIndex\"`\n\tHasUntracked bool           `json:\"HasUntracked\"`\n}\n\ntype poshGitStatus struct {\n\tAdded    []string `json:\"Added\"`\n\tModified []string `json:\"Modified\"`\n\tDeleted  []string `json:\"Deleted\"`\n\tUnmerged []string `json:\"Unmerged\"`\n}\n\nfunc (s *GitStatus) parsePoshGitStatus(p *poshGitStatus) {\n\tif p == nil {\n\t\treturn\n\t}\n\n\ts.Added = len(p.Added)\n\ts.Deleted = len(p.Deleted)\n\ts.Modified = len(p.Modified)\n\ts.Unmerged = len(p.Unmerged)\n}\n\nfunc (g *Git) hasPoshGitStatus() bool {\n\tenvStatus := g.env.Getenv(poshGitEnv)\n\tif envStatus == \"\" {\n\t\tlog.Error(fmt.Errorf(\"%s environment variable not set, do you have the posh-git module installed?\", poshGitEnv))\n\t\treturn false\n\t}\n\n\tvar posh poshGit\n\terr := json.Unmarshal([]byte(envStatus), &posh)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tg.setDir(posh.GitDir)\n\tg.Working = &GitStatus{}\n\tg.Working.parsePoshGitStatus(posh.Working)\n\tg.Staging = &GitStatus{}\n\tg.Staging.parsePoshGitStatus(posh.Index)\n\tg.HEAD = g.parsePoshGitHEAD(posh.Branch)\n\tg.stashCount = posh.StashCount\n\tg.Ahead = posh.AheadBy\n\tg.Behind = posh.BehindBy\n\tg.UpstreamGone = posh.Upstream == \"\"\n\tg.Upstream = posh.Upstream\n\n\tg.setBranchStatus()\n\n\tif len(g.Upstream) != 0 && g.options.Bool(FetchUpstreamIcon, false) {\n\t\tg.UpstreamIcon = g.getUpstreamIcon()\n\t}\n\n\tg.poshgit = true\n\treturn true\n}\n\nfunc (g *Git) parsePoshGitHEAD(head string) string {\n\t// commit\n\tif strings.HasSuffix(head, \"...)\") {\n\t\thead = strings.TrimLeft(head, \"(\")\n\t\thead = strings.TrimRight(head, \".)\")\n\t\treturn fmt.Sprintf(\"%s%s\", g.options.String(CommitIcon, \"\\uF417\"), head)\n\t}\n\t// tag\n\tif strings.HasPrefix(head, \"(\") {\n\t\thead = strings.TrimLeft(head, \"(\")\n\t\thead = strings.TrimRight(head, \")\")\n\t\treturn fmt.Sprintf(\"%s%s\", g.options.String(TagIcon, \"\\uF412\"), head)\n\t}\n\t// regular branch\n\treturn fmt.Sprintf(\"%s%s\", g.options.String(BranchIcon, \"\\uE0A0\"), g.formatBranch(head))\n}\n"
  },
  {
    "path": "src/segments/posh_git_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPoshGitSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase              string\n\t\tPoshGitJSON       string\n\t\tTemplate          string\n\t\tExpectedString    string\n\t\tFetchUpstreamIcon bool\n\t\tExpectedEnabled   bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no status\",\n\t\t\tPoshGitJSON:     \"\",\n\t\t\tExpectedString:  \"my prompt\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"invalid data\",\n\t\t\tPoshGitJSON:     \"{\",\n\t\t\tExpectedString:  \"my prompt\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase: \"Changes in Working\",\n\t\t\tPoshGitJSON: `\n\t\t\t{\n\t\t\t\t\"RepoName\": \"oh-my-posh\",\n\t\t\t\t\"HasIndex\": false,\n\t\t\t\t\"GitDir\": \"/Users/bill/Code/oh-my-posh/.git\",\n\t\t\t\t\"Upstream\": \"origin/posh-git-json\",\n\t\t\t\t\"UpstreamGone\": false,\n\t\t\t\t\"HasUntracked\": false,\n\t\t\t\t\"AheadBy\": 0,\n\t\t\t\t\"StashCount\": 0,\n\t\t\t\t\"HasWorking\": true,\n\t\t\t\t\"BehindBy\": 0,\n\t\t\t\t\"Index\": {\n\t\t\t\t\t\"value\": [],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Working\": {\n\t\t\t\t\t\"value\": [\n\t\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [\n\t\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Branch\": \"posh-git-json\"\n\t\t\t}\n\t\t\t`,\n\t\t\tExpectedString:  \"\\ue0a0posh-git-json ≡ \\uf044 ~2\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Changes in Working and Staging, branch ahead and behind\",\n\t\t\tPoshGitJSON: `\n\t\t\t{\n\t\t\t\t\"RepoName\": \"oh-my-posh\",\n\t\t\t\t\"HasIndex\": false,\n\t\t\t\t\"GitDir\": \"/Users/bill/Code/oh-my-posh/.git\",\n\t\t\t\t\"Upstream\": \"origin/posh-git-json\",\n\t\t\t\t\"UpstreamGone\": false,\n\t\t\t\t\"HasUntracked\": false,\n\t\t\t\t\"AheadBy\": 1,\n\t\t\t\t\"StashCount\": 2,\n\t\t\t\t\"HasWorking\": true,\n\t\t\t\t\"BehindBy\": 1,\n\t\t\t\t\"Index\": {\n\t\t\t\t\t\"value\": [\n\t\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Deleted\": [\n\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Modified\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Working\": {\n\t\t\t\t\t\"value\": [\n\t\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [\n\t\t\t\t\t\t\"../src/segments/git_test.go\",\n\t\t\t\t\t\t\"../src/segments/posh_git_test.go\"\n\t\t\t\t\t],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Branch\": \"posh-git-json\"\n\t\t\t}\n\t\t\t`,\n\t\t\tExpectedString:  \"\\ue0a0posh-git-json ↑1 ↓1 \\uf044 ~2 | \\uf046 -2\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Clean branch, no upstream and stash count\",\n\t\t\tPoshGitJSON: `\n\t\t\t{\n\t\t\t\t\"RepoName\": \"oh-my-posh\",\n\t\t\t\t\"GitDir\": \"/Users/bill/Code/oh-my-posh/.git\",\n\t\t\t\t\"StashCount\": 2,\n\t\t\t\t\"Index\": {\n\t\t\t\t\t\"value\": [],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Working\": {\n\t\t\t\t\t\"value\": [],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Branch\": \"posh-git-json\"\n\t\t\t}\n\t\t\t`,\n\t\t\tExpectedString:  \"\\ue0a0posh-git-json ≢\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"No working data\",\n\t\t\tPoshGitJSON: `\n\t\t\t{\n\t\t\t\t\"RepoName\": \"oh-my-posh\",\n\t\t\t\t\"GitDir\": \"/Users/bill/Code/oh-my-posh/.git\",\n\t\t\t\t\"StashCount\": 2,\n\t\t\t\t\"Index\": {\n\t\t\t\t\t\"value\": [],\n\t\t\t\t\t\"Added\": [],\n\t\t\t\t\t\"Modified\": [],\n\t\t\t\t\t\"Deleted\": [],\n\t\t\t\t\t\"Unmerged\": []\n\t\t\t\t},\n\t\t\t\t\"Branch\": \"posh-git-json\"\n\t\t\t}\n\t\t\t`,\n\t\t\tExpectedString:  \"\\ue0a0posh-git-json ≢\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Fetch upstream icon (GitHub)\",\n\t\t\tTemplate: \"{{ .UpstreamIcon }}\",\n\t\t\tPoshGitJSON: `\n\t\t\t{\n\t\t\t\t\"RepoName\": \"oh-my-posh\",\n\t\t\t\t\"GitDir\": \"/Users/bill/Code/oh-my-posh/.git\",\n\t\t\t\t\"Branch\": \"\\ue0a0posh-git-json\",\n\t\t\t\t\"Upstream\": \"origin/posh-git-json\"\n\t\t\t}\n\t\t\t`,\n\t\t\tExpectedString:    \"\\uf408\",\n\t\t\tFetchUpstreamIcon: true,\n\t\t\tExpectedEnabled:   true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Getenv\", poshGitEnv).Return(tc.PoshGitJSON)\n\t\tenv.On(\"Home\").Return(\"/Users/bill\")\n\t\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\t\tenv.On(\"RunCommand\", \"git\", []string{\"-C\", \"\", \"--no-optional-locks\", \"-c\", \"core.quotepath=false\",\n\t\t\t\"-c\", \"color.status=false\", \"remote\", \"get-url\", origin}).Return(\"github.com/cli\", nil)\n\n\t\tprops := &options.Map{\n\t\t\tFetchUpstreamIcon: tc.FetchUpstreamIcon,\n\t\t}\n\n\t\tg := &Git{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: GITCOMMAND,\n\t\t\t},\n\t\t}\n\t\tg.Init(props, env)\n\n\t\tg.configOnce = sync.Once{}\n\t\tg.configOnce.Do(func() {\n\t\t\tg.configErr = errors.New(\"no config\")\n\t\t})\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = g.Template()\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, g.hasPoshGitStatus(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, g), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestParsePoshGitHEAD(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tHEAD           string\n\t\tExpectedString string\n\t}{\n\t\t{\n\t\t\tCase:           \"branch\",\n\t\t\tHEAD:           \"main\",\n\t\t\tExpectedString: \"\\ue0a0main\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"tag\",\n\t\t\tHEAD:           \"(tag)\",\n\t\t\tExpectedString: \"\\uf412tag\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"commit\",\n\t\t\tHEAD:           \"(commit...)\",\n\t\t\tExpectedString: \"\\uf417commit\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tg := &Git{}\n\t\tg.Init(&options.Map{}, new(mock.Environment))\n\n\t\tassert.Equal(t, tc.ExpectedString, g.parsePoshGitHEAD(tc.HEAD), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/project.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/gookit/goutil/jsonutil\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\ttoml \"github.com/pelletier/go-toml/v2\"\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\ntype ProjectItem struct {\n\tFetcher func(item ProjectItem) *ProjectData\n\tName    string\n\tFiles   []string\n}\n\ntype ProjectData struct {\n\tType    string\n\tVersion string\n\tName    string\n\tTarget  string\n}\n\n// Rust Cargo package\ntype CargoTOML struct {\n\tPackage ProjectData\n}\n\n// Python package\ntype PyProjectTOML struct {\n\tProject ProjectData\n\tTool    PyProjectToolTOML\n}\n\ntype PyProjectToolTOML struct {\n\tPoetry ProjectData\n}\n\ntype NuSpec struct {\n\tXMLName  xml.Name `xml:\"package\"`\n\tMetaData struct {\n\t\tTitle   string `xml:\"title\"`\n\t\tVersion string `xml:\"version\"`\n\t} `xml:\"metadata\"`\n}\n\ntype Project struct {\n\tBase\n\n\tProjectData\n\tError    string\n\tprojects []*ProjectItem\n}\n\nfunc (n *Project) Enabled() bool {\n\tn.projects = []*ProjectItem{\n\t\t{\n\t\t\tName:    \"node\",\n\t\t\tFiles:   []string{\"package.json\"},\n\t\t\tFetcher: n.getNodePackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"deno\",\n\t\t\tFiles:   []string{\"deno.json\", \"deno.jsonc\"},\n\t\t\tFetcher: n.getDenoPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"jsr\",\n\t\t\tFiles:   []string{\"jsr.json\", \"jsr.jsonc\"},\n\t\t\tFetcher: n.getJsrPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"cargo\",\n\t\t\tFiles:   []string{\"Cargo.toml\"},\n\t\t\tFetcher: n.getCargoPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"python\",\n\t\t\tFiles:   []string{\"pyproject.toml\"},\n\t\t\tFetcher: n.getPythonPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"mojo\",\n\t\t\tFiles:   []string{\"mojoproject.toml\"},\n\t\t\tFetcher: n.getPythonPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"php\",\n\t\t\tFiles:   []string{\"composer.json\"},\n\t\t\tFetcher: n.getNodePackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"dart\",\n\t\t\tFiles:   []string{\"pubspec.yaml\"},\n\t\t\tFetcher: n.getDartPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"nuspec\",\n\t\t\tFiles:   []string{\"*.nuspec\"},\n\t\t\tFetcher: n.getNuSpecPackage,\n\t\t},\n\t\t{\n\t\t\tName:    \"dotnet\",\n\t\t\tFiles:   []string{\"*.sln\", \"*.slnf\", \"*.slnx\", \"*.vbproj\", \"*.fsproj\", \"*.csproj\"},\n\t\t\tFetcher: n.getDotnetProject,\n\t\t},\n\t\t{\n\t\t\tName:    \"julia\",\n\t\t\tFiles:   []string{\"JuliaProject.toml\", \"Project.toml\"},\n\t\t\tFetcher: n.getProjectData,\n\t\t},\n\t\t{\n\t\t\tName:    \"powershell\",\n\t\t\tFiles:   []string{\"*.psd1\"},\n\t\t\tFetcher: n.getPowerShellModuleData,\n\t\t},\n\t}\n\n\tfor _, item := range n.projects {\n\t\t// allow files override\n\t\tproperty := options.Option(fmt.Sprintf(\"%s_files\", item.Name))\n\t\titem.Files = n.options.StringArray(property, item.Files)\n\n\t\tif !n.hasProjectFile(item) {\n\t\t\tcontinue\n\t\t}\n\n\t\tdata := item.Fetcher(*item)\n\t\tif data == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tn.ProjectData = *data\n\t\tn.Type = item.Name\n\t\treturn true\n\t}\n\n\treturn n.options.Bool(options.AlwaysEnabled, false)\n}\n\nfunc (n *Project) Template() string {\n\treturn \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\\uf487 {{.Version}} {{ end }}{{ if .Name }}{{ .Name }} {{ end }}{{ if .Target }}\\uf4de {{.Target}} {{ end }}{{ end }}\" //nolint:lll\n}\n\nfunc (n *Project) hasProjectFile(p *ProjectItem) bool {\n\treturn slices.ContainsFunc(p.Files, n.env.HasFiles)\n}\n\nfunc (n *Project) getNodePackage(item ProjectItem) *ProjectData {\n\treturn n.getJSONPackage(item, false)\n}\n\nfunc (n *Project) getDenoPackage(item ProjectItem) *ProjectData {\n\tdata := n.getJSONPackage(item, true)\n\tif data == nil {\n\t\treturn nil\n\t}\n\n\t// Deno projects prefer to publish via JSR; merge JSR metadata when available.\n\tjsrFile := n.firstExistingFile([]string{\"jsr.json\", \"jsr.jsonc\"})\n\tif len(jsrFile) == 0 {\n\t\treturn data\n\t}\n\n\tjsrData, err := n.parseJSONPackage(jsrFile, true)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn data\n\t}\n\n\tif len(jsrData.Version) != 0 {\n\t\tdata.Version = jsrData.Version\n\t}\n\n\tif len(jsrData.Name) != 0 {\n\t\tdata.Name = jsrData.Name\n\t}\n\n\treturn data\n}\n\nfunc (n *Project) getJsrPackage(item ProjectItem) *ProjectData {\n\treturn n.getJSONPackage(item, true)\n}\n\nfunc (n *Project) getCargoPackage(item ProjectItem) *ProjectData {\n\tcontent := n.env.FileContent(item.Files[0])\n\n\tvar data CargoTOML\n\terr := toml.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\treturn &ProjectData{\n\t\tVersion: data.Package.Version,\n\t\tName:    data.Package.Name,\n\t}\n}\n\nfunc (n *Project) getPythonPackage(item ProjectItem) *ProjectData {\n\tcontent := n.env.FileContent(item.Files[0])\n\n\tvar data PyProjectTOML\n\terr := toml.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\tif len(data.Tool.Poetry.Version) != 0 || len(data.Tool.Poetry.Name) != 0 {\n\t\treturn &ProjectData{\n\t\t\tVersion: data.Tool.Poetry.Version,\n\t\t\tName:    data.Tool.Poetry.Name,\n\t\t}\n\t}\n\treturn &ProjectData{\n\t\tVersion: data.Project.Version,\n\t\tName:    data.Project.Name,\n\t}\n}\n\nfunc (n *Project) getDartPackage(item ProjectItem) *ProjectData {\n\tcontent := n.env.FileContent(item.Files[0])\n\tvar data ProjectData\n\terr := yaml.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\treturn &data\n}\n\nfunc (n *Project) getNuSpecPackage(_ ProjectItem) *ProjectData {\n\tfiles := n.env.LsDir(n.env.Pwd())\n\tvar content string\n\t// get the first match only\n\tfor _, file := range files {\n\t\tif filepath.Ext(file.Name()) == \".nuspec\" {\n\t\t\tcontent = n.env.FileContent(file.Name())\n\t\t\tbreak\n\t\t}\n\t}\n\n\tvar data NuSpec\n\terr := xml.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\treturn &ProjectData{\n\t\tVersion: data.MetaData.Version,\n\t\tName:    data.MetaData.Title,\n\t}\n}\n\nfunc (n *Project) getDotnetProject(item ProjectItem) *ProjectData {\n\tvar name string\n\tvar content string\n\tvar extension string\n\n\tfiles := n.env.LsDir(n.env.Pwd())\n\n\textensions := make([]string, len(item.Files))\n\tfor i, file := range item.Files {\n\t\t// Remove leading * and keep only the extension\n\t\textensions[i] = strings.TrimPrefix(file, \"*\")\n\t}\n\n\t// get the first match only\n\tfor _, file := range files {\n\t\textension = filepath.Ext(file.Name())\n\t\tif slices.Contains(extensions, extension) {\n\t\t\tname = strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))\n\t\t\tcontent = n.env.FileContent(file.Name())\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// the name of the parameter may differ depending on the version,\n\t// so instead of xml.Unmarshal() we use regex:\n\tvar target string\n\ttag := \"(?P<TAG><.*TargetFramework.*>(?P<TFM>.*)</.*TargetFramework.*>)\"\n\n\tvalues := regex.FindNamedRegexMatch(tag, content)\n\tif len(values) != 0 {\n\t\ttarget = values[\"TFM\"]\n\t}\n\n\tif target == \"\" {\n\t\tlog.Error(fmt.Errorf(\"cannot extract TFM from %s project file\", name))\n\t}\n\n\treturn &ProjectData{\n\t\tTarget: target,\n\t\tName:   name,\n\t}\n}\n\nfunc (n *Project) getPowerShellModuleData(_ ProjectItem) *ProjectData {\n\tfiles := n.env.LsDir(n.env.Pwd())\n\tvar content string\n\t// get the first match only\n\t// excluding PSScriptAnalyzerSettings.psd1\n\tfor _, file := range files {\n\t\tif filepath.Ext(file.Name()) == \".psd1\" && file.Name() != \"PSScriptAnalyzerSettings.psd1\" {\n\t\t\tcontent = n.env.FileContent(file.Name())\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif content == \"\" {\n\t\treturn nil\n\t}\n\n\tdata := &ProjectData{}\n\tlines := strings.SplitSeq(content, \"\\n\")\n\n\tfor line := range lines {\n\t\tkey, value, found := strings.Cut(line, \"=\")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\t\tkey = strings.TrimSpace(key)\n\t\tvalue = strings.TrimSpace(value)\n\t\tvalue = strings.Trim(value, \"'\\\"\")\n\n\t\tswitch key {\n\t\tcase \"ModuleVersion\":\n\t\t\tdata.Version = value\n\t\tcase \"RootModule\":\n\t\t\tdata.Name = strings.TrimRight(value, \".psm1\")\n\t\t}\n\t}\n\n\treturn data\n}\n\nfunc (n *Project) getProjectData(item ProjectItem) *ProjectData {\n\tcontent := n.env.FileContent(item.Files[0])\n\n\tvar data ProjectData\n\terr := toml.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\treturn &data\n}\n\nfunc (n *Project) getJSONPackage(item ProjectItem, allowJSONC bool) *ProjectData {\n\tfile := n.firstExistingFile(item.Files)\n\tif len(file) == 0 {\n\t\treturn nil\n\t}\n\n\tdata, err := n.parseJSONPackage(file, allowJSONC)\n\tif err != nil {\n\t\tn.Error = err.Error()\n\t\treturn nil\n\t}\n\n\treturn data\n}\n\nfunc (n *Project) firstExistingFile(files []string) string {\n\tfor _, file := range files {\n\t\tif !n.env.HasFiles(file) {\n\t\t\tcontinue\n\t\t}\n\t\treturn file\n\t}\n\n\treturn \"\"\n}\n\nfunc (n *Project) parseJSONPackage(file string, allowJSONC bool) (*ProjectData, error) {\n\tcontent := n.env.FileContent(file)\n\tif allowJSONC && filepath.Ext(file) == \".jsonc\" {\n\t\tcontent = jsonutil.StripComments(content)\n\t}\n\n\tvar data ProjectData\n\terr := json.Unmarshal([]byte(content), &data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &data, nil\n}\n"
  },
  {
    "path": "src/segments/project_test.go",
    "content": "package segments\n\nimport (\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/alecthomas/assert\"\n\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\nconst (\n\thasFiles = \"HasFiles\"\n)\n\ntype MockDirEntry struct {\n\tfileInfo fs.FileInfo\n\terr      error\n\tname     string\n\tfileMode fs.FileMode\n\tisDir    bool\n}\n\nfunc (m *MockDirEntry) Name() string {\n\treturn m.name\n}\n\nfunc (m *MockDirEntry) IsDir() bool {\n\treturn m.isDir\n}\n\nfunc (m *MockDirEntry) Type() fs.FileMode {\n\treturn m.fileMode\n}\n\nfunc (m *MockDirEntry) Info() (fs.FileInfo, error) {\n\treturn m.fileInfo, m.err\n}\n\nfunc TestPackage(t *testing.T) {\n\tcases := []struct {\n\t\tName            string\n\t\tCase            string\n\t\tFile            string\n\t\tPackageContents string\n\t\tExpectedString  string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"1.0.0 node.js\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"node\",\n\t\t\tFile:            \"package.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\",\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 deno\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\",\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 deno jsonc\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.jsonc\",\n\t\t\tPackageContents: \"{\\n// comment\\n\\\"version\\\":\\\"1.0.0\\\",\\n\\\"name\\\":\\\"test\\\"\\n}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 jsr\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 @scope/library\",\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\",\\\"name\\\":\\\"@scope/library\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 jsr jsonc\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 @scope/library\",\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.jsonc\",\n\t\t\tPackageContents: \"{\\n// comment\\n\\\"version\\\":\\\"1.0.0\\\",\\n\\\"name\\\":\\\"@scope/library\\\"\\n}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 php\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"php\",\n\t\t\tFile:            \"composer.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\",\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 node.js\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"node\", File: \"package.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"3.2.1\\\",\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 dart\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"name: test\\nversion: 1.0.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 dart\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"name: test\\nversion: 3.2.1\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 cargo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"[package]\\nname=\\\"test\\\"\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 cargo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"[package]\\nname=\\\"test\\\"\\nversion=\\\"3.2.1\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 python (poetry)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[tool.poetry]\\nname=\\\"test\\\"\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 python (poetry)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[tool.poetry]\\nname=\\\"test\\\"\\nversion=\\\"3.2.1\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 python (pep621)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 python (pep621)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\nversion=\\\"3.2.1\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"1.0.0 mojo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0 test\",\n\t\t\tName:            \"mojo\",\n\t\t\tFile:            \"mojoproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"3.2.1 mojo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 3.2.1 test\",\n\t\t\tName:            \"mojo\",\n\t\t\tFile:            \"mojoproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\nversion=\\\"3.2.1\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present node.js\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"node\",\n\t\t\tFile:            \"package.json\",\n\t\t\tPackageContents: \"{\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present deno\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.json\",\n\t\t\tPackageContents: \"{\\\"name\\\":\\\"test\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present jsr\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"@scope/library\",\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.json\",\n\t\t\tPackageContents: \"{\\\"name\\\":\\\"@scope/library\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present dart\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"name: test\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present cargo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"[package]\\nname=\\\"test\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present python (poetry)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[tool.poetry]\\nname=\\\"test\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present python (pep621)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No version present mojo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"test\",\n\t\t\tName:            \"mojo\",\n\t\t\tFile:            \"mojoproject.toml\",\n\t\t\tPackageContents: \"[project]\\nname=\\\"test\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present node.js\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"node\",\n\t\t\tFile:            \"package.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present deno\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present jsr\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.json\",\n\t\t\tPackageContents: \"{\\\"version\\\":\\\"1.0.0\\\"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present dart\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"version: 1.0.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present cargo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"[package]\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present python (poetry)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[tool.poetry]\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present python (pep621)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"[project]\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"No name present mojo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0\",\n\t\t\tName:            \"mojo\",\n\t\t\tFile:            \"mojoproject.toml\",\n\t\t\tPackageContents: \"[project]\\nversion=\\\"1.0.0\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package node.js\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"node\",\n\t\t\tFile:            \"package.json\",\n\t\t\tPackageContents: \"{}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package deno\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.json\",\n\t\t\tPackageContents: \"{}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package jsr\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.json\",\n\t\t\tPackageContents: \"{}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package dart\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package cargo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package python\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"python\",\n\t\t\tFile:            \"pyproject.toml\",\n\t\t\tPackageContents: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty project package mojo\",\n\t\t\tExpectedEnabled: true,\n\t\t\tName:            \"mojo\",\n\t\t\tFile:            \"mojoproject.toml\",\n\t\t\tPackageContents: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid json\",\n\t\t\tExpectedString:  \"invalid character '}' looking for beginning of value\",\n\t\t\tName:            \"node\",\n\t\t\tFile:            \"package.json\",\n\t\t\tPackageContents: \"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid json deno\",\n\t\t\tExpectedString:  \"invalid character '}' looking for beginning of value\",\n\t\t\tName:            \"deno\",\n\t\t\tFile:            \"deno.json\",\n\t\t\tPackageContents: \"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid json jsr\",\n\t\t\tExpectedString:  \"invalid character '}' looking for beginning of value\",\n\t\t\tName:            \"jsr\",\n\t\t\tFile:            \"jsr.json\",\n\t\t\tPackageContents: \"}\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid toml\",\n\t\t\tExpectedString:  \"toml: line 1: unexpected end of table name (table names cannot be empty)\",\n\t\t\tName:            \"cargo\",\n\t\t\tFile:            \"Cargo.toml\",\n\t\t\tPackageContents: \"[\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid yaml\",\n\t\t\tExpectedString:  \"[1:1] sequence was used where mapping is expected\\n>  1 | [\\n       ^\",\n\t\t\tName:            \"dart\",\n\t\t\tFile:            \"pubspec.yaml\",\n\t\t\tPackageContents: \"[\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Julia project\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 0.1.0 ProjectEuler\",\n\t\t\tName:            \"julia\",\n\t\t\tFile:            \"JuliaProject.toml\",\n\t\t\tPackageContents: \"name = \\\"ProjectEuler\\\"\\nversion = \\\"0.1.0\\\"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Julia project no name\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 0.1.0\",\n\t\t\tName:            \"julia\",\n\t\t\tFile:            \"JuliaProject.toml\",\n\t\t\tPackageContents: \"version = \\\"0.1.0\\\"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Julia project no version\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"ProjectEuler\",\n\t\t\tName:            \"julia\",\n\t\t\tFile:            \"JuliaProject.toml\",\n\t\t\tPackageContents: \"name = \\\"ProjectEuler\\\"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Julia project invalid toml\",\n\t\t\tExpectedString:  \"toml: line 1: unexpected end of table name (table names cannot be empty)\",\n\t\t\tName:            \"julia\",\n\t\t\tFile:            \"JuliaProject.toml\",\n\t\t\tPackageContents: \"[\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(hasFiles, testify_.Anything).Run(func(args testify_.Arguments) {\n\t\t\tfor _, c := range env.ExpectedCalls {\n\t\t\t\tif c.Method == hasFiles {\n\t\t\t\t\tc.ReturnArguments = testify_.Arguments{args.Get(0).(string) == tc.File}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tenv.On(\"FileContent\", tc.File).Return(tc.PackageContents)\n\t\tpkg := &Project{}\n\t\tpkg.Init(options.Map{}, env)\n\t\tassert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestDenoProjectUsesJsrMetadata(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(hasFiles, \"deno.json\").Return(true)\n\tenv.On(hasFiles, \"deno.jsonc\").Return(false)\n\tenv.On(hasFiles, \"jsr.json\").Return(true)\n\tenv.On(hasFiles, \"jsr.jsonc\").Return(false)\n\tenv.On(hasFiles, testify_.Anything).Return(false)\n\tenv.On(\"FileContent\", \"deno.json\").Return(\"{\\\"name\\\":\\\"library\\\"}\")\n\tenv.On(\"FileContent\", \"jsr.json\").Return(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"name\\\":\\\"@scope/library\\\"}\")\n\n\tpkg := &Project{}\n\tpkg.Init(options.Map{}, env)\n\n\tassert.True(t, pkg.Enabled())\n\tassert.Equal(t, \"\\uf487 1.0.0 @scope/library\", renderTemplate(env, pkg.Template(), pkg))\n}\n\nfunc TestNuspecPackage(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tFileName        string\n\t\tExpectedString  string\n\t\tHasFiles        bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"valid file\",\n\t\t\tFileName:        \"../test/valid.nuspec\",\n\t\t\tHasFiles:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 0.1.0 Az.Compute\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"invalid file\",\n\t\t\tFileName:        \"../test/invalid.nuspec\",\n\t\t\tHasFiles:        true,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no info in file\",\n\t\t\tFileName:        \"../test/empty.nuspec\",\n\t\t\tHasFiles:        true,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no files\",\n\t\t\tHasFiles:        false,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(hasFiles, testify_.Anything).Run(func(args testify_.Arguments) {\n\t\t\tfor _, c := range env.ExpectedCalls {\n\t\t\t\tif c.Method != hasFiles {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif args.Get(0).(string) == \"*.nuspec\" {\n\t\t\t\t\tc.ReturnArguments = testify_.Arguments{tc.HasFiles}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tc.ReturnArguments = testify_.Arguments{false}\n\t\t\t}\n\t\t})\n\t\tenv.On(\"Pwd\").Return(\"posh\")\n\t\tenv.On(\"LsDir\", \"posh\").Return([]fs.DirEntry{\n\t\t\t&MockDirEntry{\n\t\t\t\tname: tc.FileName,\n\t\t\t},\n\t\t})\n\t\tcontent, _ := os.ReadFile(tc.FileName)\n\t\tenv.On(\"FileContent\", tc.FileName).Return(string(content))\n\t\tpkg := &Project{}\n\t\tpkg.Init(options.Map{}, env)\n\t\tassert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestDotnetProject(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tFileName        string\n\t\tProjectContents string\n\t\tExpectedString  string\n\t\tHasFiles        bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"valid .csproj file\",\n\t\t\tFileName:        \"Valid.csproj\",\n\t\t\tHasFiles:        true,\n\t\t\tProjectContents: \"...<TargetFramework>net7.0</TargetFramework>...\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Valid \\uf4de net7.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"valid .fsproj file\",\n\t\t\tFileName:        \"Valid.fsproj\",\n\t\t\tHasFiles:        true,\n\t\t\tProjectContents: \"...<TargetFramework>net6.0</TargetFramework>...\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Valid \\uf4de net6.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"valid .vbproj file\",\n\t\t\tFileName:        \"Valid.vbproj\",\n\t\t\tHasFiles:        true,\n\t\t\tProjectContents: \"...<TargetFramework>net5.0</TargetFramework>...\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Valid \\uf4de net5.0\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"invalid or empty contents\",\n\t\t\tFileName:        \"Invalid.csproj\",\n\t\t\tHasFiles:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"Invalid\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"no files\",\n\t\t\tHasFiles:        false,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(hasFiles, testify_.Anything).Run(func(args testify_.Arguments) {\n\t\t\tfor _, c := range env.ExpectedCalls {\n\t\t\t\tif c.Method == hasFiles {\n\t\t\t\t\tpattern := \"*\" + filepath.Ext(tc.FileName)\n\t\t\t\t\tc.ReturnArguments = testify_.Arguments{args.Get(0).(string) == pattern}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tenv.On(\"Pwd\").Return(\"posh\")\n\t\tenv.On(\"LsDir\", \"posh\").Return([]fs.DirEntry{\n\t\t\t&MockDirEntry{\n\t\t\t\tname: tc.FileName,\n\t\t\t},\n\t\t})\n\t\tenv.On(\"FileContent\", tc.FileName).Return(tc.ProjectContents)\n\t\tpkg := &Project{}\n\t\tpkg.Init(options.Map{}, env)\n\t\tassert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestPowerShellModuleProject(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tHasFiles        bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"valid PowerShell module file\",\n\t\t\tHasFiles:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"\\uf487 1.0.0.0 oh-my-posh\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(hasFiles, testify_.Anything).Run(func(args testify_.Arguments) {\n\t\t\tfor _, c := range env.ExpectedCalls {\n\t\t\t\tif c.Method == hasFiles {\n\t\t\t\t\tc.ReturnArguments = testify_.Arguments{args.Get(0).(string) == \"*.psd1\"}\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t\tenv.On(\"Pwd\").Return(\"posh\")\n\t\tenv.On(\"LsDir\", \"posh\").Return([]fs.DirEntry{\n\t\t\t&MockDirEntry{\n\t\t\t\tname: \"oh-my-posh.psd1\",\n\t\t\t},\n\t\t})\n\t\tvar moduleContent string\n\t\tif tc.HasFiles {\n\t\t\tcontent, _ := os.ReadFile(\"../test/oh-my-posh.psd1\")\n\t\t\tmoduleContent = string(content)\n\t\t}\n\t\tenv.On(\"FileContent\", \"oh-my-posh.psd1\").Return(moduleContent)\n\t\tpkg := &Project{}\n\t\tpkg.Init(options.Map{}, env)\n\t\tassert.Equal(t, tc.ExpectedEnabled, pkg.Enabled(), tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, pkg.Template(), pkg), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/pulumi.go",
    "content": "package segments\n\nimport (\n\t\"crypto/sha1\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\nconst (\n\tFetchStack options.Option = \"fetch_stack\"\n\tFetchAbout options.Option = \"fetch_about\"\n\n\tJSON string = \"json\"\n\tYAML string = \"yaml\"\n\n\tpulumiJSON string = \"Pulumi.json\"\n\tpulumiYAML string = \"Pulumi.yaml\"\n)\n\ntype Pulumi struct {\n\tBase\n\n\tStack string\n\tName  string\n\n\tworkspaceSHA1 string\n\n\tBackend\n}\n\ntype Backend struct {\n\tURL  string `json:\"url\"`\n\tUser string `json:\"user\"`\n}\n\ntype pulumiFileSpec struct {\n\tName string `yaml:\"name\" json:\"name\"`\n}\n\ntype pulumiWorkSpaceFileSpec struct {\n\tStack string `json:\"stack\"`\n}\n\nfunc (p *Pulumi) Template() string {\n\treturn \"\\ue873 {{ .Stack }}{{if .User }} :: {{ .User }}@{{ end }}{{ if .URL }}{{ .URL }}{{ end }}\"\n}\n\nfunc (p *Pulumi) Enabled() bool {\n\tif !p.env.HasCommand(\"pulumi\") {\n\t\treturn false\n\t}\n\n\terr := p.getProjectName()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tif p.options.Bool(FetchStack, false) {\n\t\tp.getPulumiStackName()\n\t}\n\n\tif p.options.Bool(FetchAbout, false) {\n\t\tp.getPulumiAbout()\n\t}\n\n\treturn true\n}\n\nfunc (p *Pulumi) getPulumiStackName() {\n\tif p.Name == \"\" || p.workspaceSHA1 == \"\" {\n\t\tlog.Debug(\"pulumi project name or workspace sha1 is empty\")\n\t\treturn\n\t}\n\n\tstackNameFile := p.Name + \"-\" + p.workspaceSHA1 + \"-\" + \"workspace.json\"\n\n\thomedir := p.env.Home()\n\n\tworkspaceCacheDir := filepath.Join(homedir, \".pulumi\", \"workspaces\")\n\tif !p.env.HasFolder(workspaceCacheDir) || !p.env.HasFilesInDir(workspaceCacheDir, stackNameFile) {\n\t\treturn\n\t}\n\n\tworkspaceCacheFile := filepath.Join(workspaceCacheDir, stackNameFile)\n\tworkspaceCacheFileContent := p.env.FileContent(workspaceCacheFile)\n\n\tvar pulumiWorkspaceSpec pulumiWorkSpaceFileSpec\n\terr := json.Unmarshal([]byte(workspaceCacheFileContent), &pulumiWorkspaceSpec)\n\tif err != nil {\n\t\tlog.Error(fmt.Errorf(\"pulumi workspace file decode error\"))\n\t\treturn\n\t}\n\n\tlog.Debugf(\"pulumi stack name: %s\", pulumiWorkspaceSpec.Stack)\n\tp.Stack = pulumiWorkspaceSpec.Stack\n}\n\nfunc (p *Pulumi) getProjectName() error {\n\tvar kind, fileName string\n\tfor _, file := range []string{pulumiYAML, pulumiJSON} {\n\t\tif p.env.HasFiles(file) {\n\t\t\tfileName = file\n\t\t\tkind = filepath.Ext(file)[1:]\n\t\t}\n\t}\n\n\tif kind == \"\" {\n\t\treturn fmt.Errorf(\"no pulumi spec file found\")\n\t}\n\n\tvar pulumiFileSpec pulumiFileSpec\n\tvar err error\n\n\tpulumiFile := p.env.FileContent(fileName)\n\n\tswitch kind {\n\tcase YAML:\n\t\terr = yaml.Unmarshal([]byte(pulumiFile), &pulumiFileSpec)\n\tcase JSON:\n\t\terr = json.Unmarshal([]byte(pulumiFile), &pulumiFileSpec)\n\tdefault:\n\t\terr = fmt.Errorf(\"unknown pulumi spec file format\")\n\t}\n\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn nil\n\t}\n\n\tp.Name = pulumiFileSpec.Name\n\n\tp.workspaceSHA1 = p.sha1HexString(p.env.Pwd() + path.Separator() + fileName)\n\n\treturn nil\n}\n\nfunc (p *Pulumi) sha1HexString(s string) string {\n\th := sha1.New()\n\n\t_, err := h.Write([]byte(s))\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\"\n\t}\n\n\treturn hex.EncodeToString(h.Sum(nil))\n}\n\nfunc (p *Pulumi) getPulumiAbout() {\n\tif p.Stack == \"\" {\n\t\tlog.Error(fmt.Errorf(\"pulumi stack name is empty, use `fetch_stack` property to enable stack fetching\"))\n\t\treturn\n\t}\n\n\taboutOutput, err := p.env.RunCommand(\"pulumi\", \"about\", \"--json\")\n\n\tif err != nil {\n\t\tlog.Error(fmt.Errorf(\"unable to get pulumi about output\"))\n\t\treturn\n\t}\n\n\tvar about struct {\n\t\tBackend *Backend `json:\"backend\"`\n\t}\n\n\terr = json.Unmarshal([]byte(aboutOutput), &about)\n\tif err != nil {\n\t\tlog.Error(fmt.Errorf(\"pulumi about output decode error\"))\n\t\treturn\n\t}\n\n\tif about.Backend == nil {\n\t\tlog.Debug(\"pulumi about backend is not set\")\n\t\treturn\n\t}\n\n\tp.Backend = *about.Backend\n}\n"
  },
  {
    "path": "src/segments/pulumi_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestPulumi(t *testing.T) {\n\tcases := []struct {\n\t\tStackError         error\n\t\tAboutError         error\n\t\tAbout              string\n\t\tYAMLConfig         string\n\t\tJSONConfig         string\n\t\tCase               string\n\t\tExpectedString     string\n\t\tStack              string\n\t\tAboutCache         string\n\t\tWorkSpaceFile      string\n\t\tHasCommand         bool\n\t\tFetchAbout         bool\n\t\tHasWorkspaceFolder bool\n\t\tFetchStack         bool\n\t\tExpectedEnabled    bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no pulumi command\",\n\t\t\tExpectedEnabled: false,\n\t\t\tHasCommand:      false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"pulumi command is present, but no pulumi file\",\n\t\t\tExpectedEnabled: false,\n\t\t\tHasCommand:      true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"pulumi file YAML is present\",\n\t\t\tExpectedString:  \"\\ue873\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasCommand:      true,\n\t\t\tYAMLConfig: `\nname: oh-my-posh\nruntime: golang\ndescription: A Console App\n`,\n\t\t},\n\t\t{\n\t\t\tCase:            \"pulumi file JSON is present\",\n\t\t\tExpectedString:  \"\\ue873\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasCommand:      true,\n\t\t\tJSONConfig:      `{ \"name\": \"oh-my-posh\" }`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"no stack present\",\n\t\t\tExpectedString:     \"\\ue873 1337\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi stack\",\n\t\t\tExpectedString:     \"\\ue873 1337\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi URL\",\n\t\t\tExpectedString:     \"\\ue873 1337 :: posh-user@s3://test-pulumi-state-test\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tFetchAbout:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t\tAbout:              `{ \"backend\": { \"url\": \"s3://test-pulumi-state-test\", \"user\":\"posh-user\" } }`,\n\t\t},\n\t\t// Error flows\n\t\t{\n\t\t\tCase:            \"pulumi file JSON error\",\n\t\t\tExpectedString:  \"\\ue873\",\n\t\t\tExpectedEnabled: true,\n\t\t\tFetchStack:      true,\n\t\t\tHasCommand:      true,\n\t\t\tJSONConfig:      `{`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi workspace file JSON error\",\n\t\t\tExpectedString:     \"\\ue873\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tFetchStack:         true,\n\t\t\tHasCommand:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{`,\n\t\t\tHasWorkspaceFolder: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"pulumi URL, no fetch_stack set\",\n\t\t\tExpectedString:  \"\\ue873\",\n\t\t\tExpectedEnabled: true,\n\t\t\tHasCommand:      true,\n\t\t\tFetchAbout:      true,\n\t\t\tJSONConfig:      `{ \"name\": \"oh-my-posh\" }`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi URL - about error\",\n\t\t\tExpectedString:     \"\\ue873 1337\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tFetchAbout:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t\tAboutError:         errors.New(\"error\"),\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi URL - about decode error\",\n\t\t\tExpectedString:     \"\\ue873 1337\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tFetchAbout:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t\tAbout:              `{`,\n\t\t},\n\t\t{\n\t\t\tCase:               \"pulumi URL - about backend is nil\",\n\t\t\tExpectedString:     \"\\ue873 1337\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tHasCommand:         true,\n\t\t\tHasWorkspaceFolder: true,\n\t\t\tFetchStack:         true,\n\t\t\tFetchAbout:         true,\n\t\t\tJSONConfig:         `{ \"name\": \"oh-my-posh\" }`,\n\t\t\tWorkSpaceFile:      `{ \"stack\": \"1337\" }`,\n\t\t\tAbout:              `{}`,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\tenv.On(\"HasCommand\", \"pulumi\").Return(tc.HasCommand)\n\t\tenv.On(\"RunCommand\", \"pulumi\", []string{\"stack\", \"ls\", \"--json\"}).Return(tc.Stack, tc.StackError)\n\t\tenv.On(\"RunCommand\", \"pulumi\", []string{\"about\", \"--json\"}).Return(tc.About, tc.AboutError)\n\n\t\tpwd := \"/home/foobar/Work/oh-my-posh/pulumi/projects/awesome-project\"\n\t\tenv.On(\"Pwd\").Return(pwd)\n\t\tenv.On(\"Home\").Return(filepath.Clean(\"/home/foobar\"))\n\n\t\tenv.On(\"HasFiles\", pulumiYAML).Return(len(tc.YAMLConfig) > 0)\n\t\tenv.On(\"FileContent\", pulumiYAML).Return(tc.YAMLConfig, nil)\n\n\t\tenv.On(\"HasFiles\", pulumiJSON).Return(len(tc.JSONConfig) > 0)\n\t\tenv.On(\"FileContent\", pulumiJSON).Return(tc.JSONConfig, nil)\n\n\t\tenv.On(\"HasFolder\", filepath.Clean(\"/home/foobar/.pulumi/workspaces\")).Return(tc.HasWorkspaceFolder)\n\n\t\tpulumi := &Pulumi{}\n\n\t\tvar fileName string\n\t\tif len(tc.JSONConfig) > 0 {\n\t\t\tfileName = pulumiJSON\n\t\t} else {\n\t\t\tfileName = pulumiYAML\n\t\t}\n\n\t\tsha1 := pulumi.sha1HexString(pwd + path.Separator() + fileName)\n\t\tworkspaceFile := fmt.Sprintf(\"oh-my-posh-%s-workspace.json\", sha1)\n\n\t\tenv.On(\"HasFilesInDir\", filepath.Clean(\"/home/foobar/.pulumi/workspaces\"), workspaceFile).Return(len(tc.WorkSpaceFile) > 0)\n\n\t\tenv.On(\"FileContent\", filepath.Clean(\"/home/foobar/.pulumi/workspaces/\"+workspaceFile)).Return(tc.WorkSpaceFile, nil)\n\n\t\tprops := options.Map{\n\t\t\tFetchStack: tc.FetchStack,\n\t\t\tFetchAbout: tc.FetchAbout,\n\t\t}\n\n\t\tpulumi.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, pulumi.Enabled(), tc.Case)\n\n\t\tif !tc.ExpectedEnabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar got = renderTemplate(env, pulumi.Template(), pulumi)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/python.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"slices\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Python struct {\n\tVenv string\n\tLanguage\n}\n\nconst (\n\t// FetchVirtualEnv fetches the virtual env\n\tFetchVirtualEnv      options.Option = \"fetch_virtual_env\"\n\tUsePythonVersionFile options.Option = \"use_python_version_file\"\n\tFolderNameFallback   options.Option = \"folder_name_fallback\"\n\tDefaultVenvNames     options.Option = \"default_venv_names\"\n)\n\nfunc (p *Python) Template() string {\n\treturn \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \"\n}\n\nfunc (p *Python) Enabled() bool {\n\tp.extensions = []string{\"*.py\", \"*.ipynb\", \"pyproject.toml\", \"venv.bak\"}\n\tp.folders = []string{\".venv\", \"venv\", \"virtualenv\", \"venv-win\", \"pyenv-win\"}\n\n\t// Define all available tooling options for Python\n\tp.tooling = map[string]*cmd{\n\t\t\"pyenv\": {\n\t\t\tgetVersion: p.pyenvVersion,\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t\t\"python\": {\n\t\t\texecutable: \"python\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t\t\"python3\": {\n\t\t\texecutable: \"python3\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t\t\"py\": {\n\t\t\texecutable: \"py\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t\t\"uv\": {\n\t\t\texecutable: \"uv\",\n\t\t\targs:       []string{\"run\", \"--no-sync\", \"--quiet\", \"--no-python-downloads\", \"python\", \"--version\"},\n\t\t\tregex:      `(?:Python (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\n\t// Default tooling order - users can override via \"tooling\" option\n\tp.defaultTooling = []string{\"pyenv\", \"python\", \"python3\", \"py\"}\n\n\tp.versionURLTemplate = \"https://docs.python.org/release/{{ .Major }}.{{ .Minor }}.{{ .Patch }}/whatsnew/changelog.html#python-{{ .Major }}-{{ .Minor }}-{{ .Patch }}\"\n\tp.displayMode = p.options.String(DisplayMode, DisplayModeEnvironment)\n\tp.Language.loadContext = p.loadContext\n\tp.Language.inContext = p.inContext\n\n\treturn p.Language.Enabled()\n}\n\nfunc (p *Python) loadContext() {\n\tif !p.options.Bool(FetchVirtualEnv, true) {\n\t\treturn\n\t}\n\tif prompt := p.pyvenvCfgPrompt(); len(prompt) > 0 {\n\t\tp.Venv = prompt\n\t\treturn\n\t}\n\n\tvenvVars := []string{\n\t\t\"VIRTUAL_ENV\",\n\t\t\"CONDA_ENV_PATH\",\n\t\t\"CONDA_DEFAULT_ENV\",\n\t}\n\n\tfolderNameFallback := p.options.Bool(FolderNameFallback, true)\n\tdefaultVenvNames := p.options.StringArray(DefaultVenvNames, []string{\n\t\t\".venv\",\n\t\t\"venv\",\n\t})\n\n\tvar venv string\n\tfor _, venvVar := range venvVars {\n\t\tvenv = p.env.Getenv(venvVar)\n\t\tif venv == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tname := path.Base(venv)\n\t\tlog.Debugf(\"virtual env name: %s\", name)\n\t\tif folderNameFallback && slices.Contains(defaultVenvNames, name) {\n\t\t\tvenv = strings.TrimSuffix(venv, name)\n\t\t\tname = path.Base(venv)\n\t\t\tlog.Debugf(\"virtual env name (fallback): %s\", name)\n\t\t}\n\n\t\tif p.canUseVenvName(name) {\n\t\t\tp.Venv = name\n\t\t\tbreak\n\t\t}\n\t}\n}\n\nfunc (p *Python) inContext() bool {\n\treturn p.Venv != \"\"\n}\n\nfunc (p *Python) canUseVenvName(name string) bool {\n\tif p.options.Bool(options.DisplayDefault, true) {\n\t\treturn true\n\t}\n\n\tinvalidNames := [2]string{\"system\", \"base\"}\n\tfor _, a := range invalidNames {\n\t\tif a == name {\n\t\t\tlog.Debugf(\"virtual env name %s is invalid\", name)\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\nfunc (p *Python) pyenvVersion() (string, error) {\n\t// Use `pyenv root` instead of $PYENV_ROOT?\n\t// Is our Python executable at $PYENV_ROOT/bin/python ?\n\t// Should p.env expose command paths?\n\tcmdPath := p.env.CommandPath(\"python\")\n\tif cmdPath == \"\" {\n\t\tcmdPath = p.env.CommandPath(\"python3\")\n\t}\n\n\tif cmdPath == \"\" {\n\t\treturn \"\", errors.New(\"no python executable found\")\n\t}\n\n\tpyEnvRoot := p.env.Getenv(\"PYENV_ROOT\")\n\tif pyEnvRoot == \"\" || !strings.HasPrefix(cmdPath, pyEnvRoot) {\n\t\treturn \"\", fmt.Errorf(\"executable at %s is not a pyenv shim\", cmdPath)\n\t}\n\n\t// pyenv version-name will return current version or virtualenv\n\tcmdOutput, err := p.env.RunCommand(\"pyenv\", \"version-name\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tversionString, _, found := strings.Cut(cmdOutput, \":\")\n\tif !found || versionString == \"\" {\n\t\treturn \"\", errors.New(\"no pyenv version-name found\")\n\t}\n\n\t// $PYENV_ROOT/versions + versionString (symlinks resolved) == $PYENV_ROOT/versions/(version)[/envs/(virtualenv)]\n\trealPath, err := p.env.ResolveSymlink(filepath.Join(pyEnvRoot, \"versions\", versionString))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// ../versions/(version)[/envs/(virtualenv)]\n\tshortPath, err := filepath.Rel(filepath.Join(pyEnvRoot, \"versions\"), realPath)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// override virtualenv if pyenv set one\n\tparts := strings.SplitN(shortPath, string(filepath.Separator), 4)\n\tif len(parts) > 2 && p.canUseVenvName(parts[2]) {\n\t\tp.Venv = parts[2]\n\t}\n\n\treturn parts[0], nil\n}\n\nfunc (p *Python) pyvenvCfgPrompt() string {\n\tcmdPath := p.env.CommandPath(\"python\")\n\tif cmdPath == \"\" {\n\t\tcmdPath = p.env.CommandPath(\"python3\")\n\t}\n\n\tif cmdPath == \"\" {\n\t\treturn \"\"\n\t}\n\n\tpyvenvDir := filepath.Dir(cmdPath)\n\tif !p.env.HasFilesInDir(pyvenvDir, \"pyvenv.cfg\") {\n\t\tpyvenvDir = filepath.Dir(pyvenvDir)\n\t}\n\n\tif !p.env.HasFilesInDir(pyvenvDir, \"pyvenv.cfg\") {\n\t\treturn \"\"\n\t}\n\n\tpyvenvCfg := p.env.FileContent(filepath.Join(pyvenvDir, \"pyvenv.cfg\"))\n\tfor line := range strings.SplitSeq(pyvenvCfg, \"\\n\") {\n\t\tkey, value, found := strings.Cut(line, \"=\")\n\t\tif !found {\n\t\t\tcontinue\n\t\t}\n\n\t\tkey = strings.TrimSpace(key)\n\t\tif key == \"prompt\" {\n\t\t\tvalue := strings.TrimSpace(value)\n\t\t\treturn value\n\t\t}\n\t}\n\n\treturn \"\"\n}\n"
  },
  {
    "path": "src/segments/python_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/alecthomas/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\nfunc TestPythonTemplate(t *testing.T) {\n\ttype ResolveSymlink struct {\n\t\tErr  error\n\t\tPath string\n\t}\n\tcases := []struct {\n\t\tResolveSymlink   ResolveSymlink\n\t\tCase             string\n\t\tExpected         string\n\t\tTemplate         string\n\t\tVirtualEnvName   string\n\t\tPythonPath       string\n\t\tPyvenvCfg        string\n\t\tExpectedDisabled bool\n\t\tFetchVersion     bool\n\t}{\n\t\t{Case: \"No virtual env present\", FetchVersion: true, Expected: \"3.8.4\", Template: \"{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}\"},\n\t\t{Case: \"Virtual env present\", FetchVersion: true, Expected: \"VENV 3.8.4\", VirtualEnvName: \"VENV\", Template: \"{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}\"},\n\t\t{\n\t\t\tCase:           \"Virtual env major and minor dot\",\n\t\t\tFetchVersion:   true,\n\t\t\tExpected:       \"VENV 3.8\",\n\t\t\tVirtualEnvName: \"VENV\",\n\t\t\tTemplate:       \"{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Virtual env hide on default\",\n\t\t\tFetchVersion:   true,\n\t\t\tExpected:       \"3.8\",\n\t\t\tVirtualEnvName: \"default\",\n\t\t\tTemplate:       \"{{ if ne .Venv \\\"default\\\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Virtual env show non default\",\n\t\t\tFetchVersion:   true,\n\t\t\tExpected:       \"billy 3.8\",\n\t\t\tVirtualEnvName: \"billy\",\n\t\t\tTemplate:       \"{{ if ne .Venv \\\"default\\\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Pyenv show env\",\n\t\t\tFetchVersion:   true,\n\t\t\tExpected:       \"VENV 3.8\",\n\t\t\tPythonPath:     \"/home/user/.pyenv/shims/python\",\n\t\t\tVirtualEnvName: \"VENV\",\n\t\t\tTemplate:       \"{{ if ne .Venv \\\"default\\\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t\tResolveSymlink: ResolveSymlink{Path: \"/home/user/.pyenv/versions/3.8.8/envs/VENV\", Err: nil},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Pyenv no venv\",\n\t\t\tFetchVersion:   true,\n\t\t\tExpected:       \"3.8\",\n\t\t\tPythonPath:     \"/home/user/.pyenv/shims/python\",\n\t\t\tTemplate:       \"{{ if ne .Venv \\\"default\\\" }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t\tResolveSymlink: ResolveSymlink{Path: \"/home/user.pyenv/versions/3.8.8\", Err: nil},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Pyenv virtual env version name\",\n\t\t\tFetchVersion:   true,\n\t\t\tVirtualEnvName: \"demo\",\n\t\t\tExpected:       \"demo 3.8.4\",\n\t\t\tPythonPath:     \"/home/user/.pyenv/shims/python\",\n\t\t\tTemplate:       \"{{ .Venv }} {{ .Full }}\",\n\t\t\tResolveSymlink: ResolveSymlink{Path: \"/home/user/.pyenv/versions/demo\", Err: nil},\n\t\t},\n\t\t{\n\t\t\tCase:           \"pyvenv.cfg prompt\",\n\t\t\tFetchVersion:   true,\n\t\t\tVirtualEnvName: \"VENV\",\n\t\t\tPythonPath:     \"/home/user/.pyenv/shims/python\",\n\t\t\tTemplate:       \"{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}\",\n\t\t\tPyvenvCfg:      \"home = /usr/bin/\\nprompt = pyvenvCfgPrompt\\n\",\n\t\t\tExpected:       \"pyvenvCfgPrompt 3.8\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"python\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: \"Python 3.8.4\",\n\t\t\textension:     \"*.py\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"CommandPath\", testify_.Anything).Return(tc.PythonPath)\n\t\tenv.On(\"RunCommand\", \"pyenv\", []string{\"version-name\"}).Return(tc.VirtualEnvName, nil)\n\t\tenv.On(\"HasFilesInDir\", testify_.Anything, \"pyvenv.cfg\").Return(len(tc.PyvenvCfg) > 0)\n\t\tenv.On(\"FileContent\", filepath.Join(filepath.Dir(tc.PythonPath), \"pyvenv.cfg\")).Return(tc.PyvenvCfg)\n\t\tenv.On(\"Getenv\", \"VIRTUAL_ENV\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"CONDA_ENV_PATH\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"CONDA_DEFAULT_ENV\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"PYENV_ROOT\").Return(\"/home/user/.pyenv\")\n\t\tenv.On(\"PathSeparator\").Return(\"\")\n\t\tenv.On(\"ResolveSymlink\", testify_.Anything).Return(tc.ResolveSymlink.Path, tc.ResolveSymlink.Err)\n\n\t\tprops[options.FetchVersion] = tc.FetchVersion\n\t\tprops[UsePythonVersionFile] = true\n\t\tprops[DisplayMode] = DisplayModeAlways\n\n\t\tpython := &Python{}\n\t\tpython.Init(props, env)\n\t\tassert.Equal(t, !tc.ExpectedDisabled, python.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, python), tc.Case)\n\t}\n}\n\nfunc TestPythonPythonInContext(t *testing.T) {\n\tcases := []struct {\n\t\tVirtualEnvName string\n\t\tExpected       bool\n\t}{\n\t\t{Expected: true, VirtualEnvName: \"VENV\"},\n\t\t{Expected: false, VirtualEnvName: \"\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"CommandPath\", testify_.Anything).Return(\"\")\n\t\tenv.On(\"HasFilesInDir\", testify_.Anything, \"pyvenv.cfg\").Return(false)\n\t\tenv.On(\"Getenv\", \"VIRTUAL_ENV\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"CONDA_ENV_PATH\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"CONDA_DEFAULT_ENV\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"PYENV_VERSION\").Return(\"\")\n\t\tenv.On(\"HasParentFilePath\", \".python-version\", false).Return(&runtime.FileInfo{}, errors.New(\"no match at root level\"))\n\t\tpython := &Python{}\n\t\tpython.Init(options.Map{}, env)\n\t\tpython.loadContext()\n\t\tassert.Equal(t, tc.Expected, python.inContext())\n\t}\n}\n\nfunc TestPythonVirtualEnvIgnoreDefaultVenvNames(t *testing.T) {\n\tcases := []struct {\n\t\tExpected           string\n\t\tVirtualEnvName     string\n\t\tFolderNameFallback bool\n\t}{\n\t\t{\n\t\t\tExpected:           \"folder\",\n\t\t\tFolderNameFallback: true,\n\t\t\tVirtualEnvName:     \"/path/to/folder/.venv\",\n\t\t},\n\t\t{\n\t\t\tExpected:           \"folder\",\n\t\t\tFolderNameFallback: true,\n\t\t\tVirtualEnvName:     \"/path/to/folder/venv\",\n\t\t},\n\t\t{\n\t\t\tExpected:           \".venv\",\n\t\t\tFolderNameFallback: false,\n\t\t\tVirtualEnvName:     \"/path/to/folder/.venv\",\n\t\t},\n\t\t{\n\t\t\tExpected:           \"venv\",\n\t\t\tFolderNameFallback: false,\n\t\t\tVirtualEnvName:     \"/path/to/folder/venv\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"CommandPath\", testify_.Anything).Return(\"\")\n\t\tenv.On(\"HasFilesInDir\", testify_.Anything, \"pyvenv.cfg\").Return(false)\n\t\tenv.On(\"Getenv\", \"VIRTUAL_ENV\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"CONDA_ENV_PATH\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"CONDA_DEFAULT_ENV\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"PYENV_VERSION\").Return(\"\")\n\t\tenv.On(\"HasParentFilePath\", \".python-version\", false).Return(&runtime.FileInfo{}, errors.New(\"no match at root level\"))\n\n\t\tprops[FolderNameFallback] = tc.FolderNameFallback\n\n\t\tpython := &Python{}\n\t\tpython.Init(props, env)\n\t\tpython.loadContext()\n\t\tassert.Equal(t, tc.Expected, python.Venv)\n\t}\n}\n\nfunc TestPythonVirtualEnvIgnoreCustomVenvNames(t *testing.T) {\n\tcases := []struct {\n\t\tExpected           string\n\t\tVirtualEnvName     string\n\t\tDefaultVenvNames   []string\n\t\tFolderNameFallback bool\n\t}{\n\t\t{\n\t\t\tExpected:           \"folder\",\n\t\t\tFolderNameFallback: true,\n\t\t\tDefaultVenvNames:   []string{\"env\"},\n\t\t\tVirtualEnvName:     \"/path/to/folder/env\",\n\t\t},\n\t\t{\n\t\t\tExpected:           \"venv\",\n\t\t\tFolderNameFallback: true,\n\t\t\tDefaultVenvNames:   []string{\"env\"},\n\t\t\tVirtualEnvName:     \"/path/to/folder/venv\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"CommandPath\", testify_.Anything).Return(\"\")\n\t\tenv.On(\"HasFilesInDir\", testify_.Anything, \"pyvenv.cfg\").Return(false)\n\t\tenv.On(\"Getenv\", \"VIRTUAL_ENV\").Return(tc.VirtualEnvName)\n\t\tenv.On(\"Getenv\", \"CONDA_ENV_PATH\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"CONDA_DEFAULT_ENV\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"PYENV_VERSION\").Return(\"\")\n\t\tenv.On(\"HasParentFilePath\", \".python-version\", false).Return(&runtime.FileInfo{}, errors.New(\"no match at root level\"))\n\n\t\tprops[FolderNameFallback] = tc.FolderNameFallback\n\t\tprops[DefaultVenvNames] = tc.DefaultVenvNames\n\n\t\tpython := &Python{}\n\t\tpython.Init(props, env)\n\t\tpython.loadContext()\n\t\tassert.Equal(t, tc.Expected, python.Venv)\n\t}\n}\n\nfunc TestPythonUVTooling(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpected        string\n\t\tUVVersionOutput string\n\t\tTooling         []string\n\t\tHasUVCommand    bool\n\t}{\n\t\t{\n\t\t\tCase:            \"UV enabled and available\",\n\t\t\tExpected:        \"3.10.5\",\n\t\t\tTooling:         []string{\"uv\"},\n\t\t\tUVVersionOutput: \"Python 3.10.5\",\n\t\t\tHasUVCommand:    true,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Default tooling (no UV)\",\n\t\t\tExpected: \"3.8.4\",\n\t\t\tTooling:  nil, // Use default tooling\n\t\t},\n\t\t{\n\t\t\tCase:         \"UV enabled but not available falls back\",\n\t\t\tExpected:     \"3.8.4\",\n\t\t\tTooling:      []string{\"uv\", \"python\"},\n\t\t\tHasUVCommand: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"python\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: \"Python 3.8.4\",\n\t\t\textension:     \"*.py\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Shell\").Return(\"bash\")\n\t\tenv.On(\"CommandPath\", testify_.Anything).Return(\"\")\n\t\tenv.On(\"HasFilesInDir\", testify_.Anything, \"pyvenv.cfg\").Return(false)\n\t\tenv.On(\"Getenv\", \"VIRTUAL_ENV\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"CONDA_ENV_PATH\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"CONDA_DEFAULT_ENV\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"PYENV_VERSION\").Return(\"\")\n\t\tenv.On(\"Getenv\", \"PYENV_ROOT\").Return(\"\")\n\t\tenv.On(\"HasParentFilePath\", \".python-version\", false).Return(&runtime.FileInfo{}, errors.New(\"no match at root level\"))\n\n\t\t// Initialize template system for version URL rendering\n\t\tif template.Cache == nil {\n\t\t\ttemplate.Cache = &cache.Template{}\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tif tc.HasUVCommand {\n\t\t\tenv.On(\"HasCommand\", \"uv\").Return(true)\n\t\t\tenv.On(\"RunCommand\", \"uv\", []string{\"run\", \"--no-sync\", \"--quiet\", \"--no-python-downloads\", \"python\", \"--version\"}).Return(tc.UVVersionOutput, nil)\n\t\t} else {\n\t\t\tenv.On(\"HasCommand\", \"uv\").Return(false)\n\t\t}\n\n\t\tif tc.Tooling != nil {\n\t\t\tprops[Tooling] = tc.Tooling\n\t\t}\n\t\tprops[DisplayMode] = DisplayModeAlways\n\n\t\tpython := &Python{}\n\t\tpython.Init(props, env)\n\n\t\tassert.True(t, python.Enabled(), tc.Case)\n\n\t\t// Verify commands are built from tooling\n\t\tif len(tc.Tooling) > 0 {\n\t\t\tassert.Equal(t, tc.Tooling[0], python.commands[0].executable, tc.Case)\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, python.Full, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/quasar.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tFetchDependencies options.Option = \"fetch_dependencies\"\n)\n\ntype Package struct {\n\tVersion string `json:\"version\"`\n\tDev     bool   `json:\"dev\"`\n}\n\ntype Quasar struct {\n\tVite    *Package\n\tAppVite *Package\n\tLanguage\n\tHasVite bool\n}\n\nfunc (q *Quasar) Enabled() bool {\n\tq.projectFiles = []string{\"quasar.config\", \"quasar.config.js\"}\n\tq.tooling = map[string]*cmd{\n\t\t\"quasar\": {\n\t\t\texecutable: \"quasar\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tq.defaultTooling = []string{\"quasar\"}\n\tq.versionURLTemplate = \"https://github.com/quasarframework/quasar/releases/tag/quasar-v{{ .Full }}\"\n\n\tif !q.Language.Enabled() {\n\t\treturn false\n\t}\n\n\tif q.options.Bool(FetchDependencies, false) {\n\t\tq.fetchDependencies()\n\t}\n\n\treturn true\n}\n\nfunc (q *Quasar) Template() string {\n\treturn \" \\ue87f {{.Full}}{{ if .HasVite }} \\ueb29 {{ .Vite.Version }}{{ end }} \"\n}\n\nfunc (q *Quasar) fetchDependencies() {\n\tif !q.env.HasFilesInDir(q.projectRoot.ParentFolder, \"package-lock.json\") {\n\t\treturn\n\t}\n\n\tpackageFilePath := filepath.Join(q.projectRoot.ParentFolder, \"package-lock.json\")\n\tcontent := q.env.FileContent(packageFilePath)\n\n\tvar objmap map[string]json.RawMessage\n\tif err := json.Unmarshal([]byte(content), &objmap); err != nil {\n\t\treturn\n\t}\n\n\tvar dependencies map[string]*Package\n\tif err := json.Unmarshal(objmap[\"dependencies\"], &dependencies); err != nil {\n\t\treturn\n\t}\n\n\tif p, ok := dependencies[\"vite\"]; ok {\n\t\tq.HasVite = true\n\t\tq.Vite = p\n\t}\n\n\tif p, ok := dependencies[\"@quasar/app-vite\"]; ok {\n\t\tq.AppVite = p\n\t}\n}\n"
  },
  {
    "path": "src/segments/quasar_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nfunc TestQuasar(t *testing.T) {\n\tpackageLockFile := `{\n\t\t\"name\": \"quasar-project\",\n\t\t\"version\": \"0.0.1\",\n\t\t\"lockfileVersion\": 2,\n\t\t\"requires\": true,\n\t\t\"dependencies\": {\n\t\t\t\"@quasar/app-vite\": {\n\t\t\t\t\"version\": \"1.4.3\",\n\t\t\t\t\"resolved\": \"https://registry.npmjs.org/@quasar/app-vite/-/app-vite-1.4.3.tgz\",\n\t\t\t\t\"integrity\": \"sha512-5iMs1sk6fyYTFoRVySwFXWL/PS23UEsdk+YSFejhXnSs5fVDmb2GQMguCHwDl3jPIHjZ7A+XKkb2iWx9pjiPXw==\",\n\t\t\t\t\"dev\": true\n\t\t\t},\n\t\t\t\"vite\": {\n\t\t\t\t\"version\": \"2.9.16\",\n\t\t\t\t\"resolved\": \"https://registry.npmjs.org/vite/-/vite-2.9.16.tgz\",\n\t\t\t\t\"integrity\": \"sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA==\",\n\t\t\t\t\"dev\": true,\n\t\t\t\t\"requires\": {\n\t\t\t\t\t\"esbuild\": \"^0.14.27\",\n\t\t\t\t\t\"fsevents\": \"~2.3.2\",\n\t\t\t\t\t\"postcss\": \"^8.4.13\",\n\t\t\t\t\t\"resolve\": \"^1.22.0\",\n\t\t\t\t\t\"rollup\": \">=2.59.0 <2.78.0\"\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}`\n\n\tcases := []struct {\n\t\tCase               string\n\t\tExpectedString     string\n\t\tVersion            string\n\t\tHasPackageLockFile bool\n\t\tFetchDependencies  bool\n\t}{\n\t\t{Case: \"@quasar/cli v2.2.1\", ExpectedString: \"\\ue87f 2.2.1\", Version: \"@quasar/cli v2.2.1\"},\n\t\t{\n\t\t\tCase:               \"@quasar/cli v2.2.1 with vite\",\n\t\t\tVersion:            \"@quasar/cli v2.2.1\",\n\t\t\tHasPackageLockFile: true,\n\t\t\tFetchDependencies:  true,\n\t\t\tExpectedString:     \"\\ue87f 2.2.1 \\ueb29 2.9.16\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"quasar\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"quasar.config\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"HasFilesInDir\", \"/usr/home/project\", \"package-lock.json\").Return(tc.HasPackageLockFile)\n\t\tfileInfo := &runtime.FileInfo{ParentFolder: \"/usr/home/project\", IsDir: true}\n\t\tenv.On(\"HasParentFilePath\", \"quasar.config\", false).Return(fileInfo, nil)\n\t\tenv.On(\"FileContent\", filepath.Join(fileInfo.ParentFolder, \"package-lock.json\")).Return(packageLockFile)\n\n\t\tprops[FetchDependencies] = tc.FetchDependencies\n\n\t\tquasar := &Quasar{}\n\t\tquasar.Init(props, env)\n\n\t\tassert.True(t, quasar.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, quasar.Template(), quasar), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/r.go",
    "content": "package segments\n\ntype R struct {\n\tLanguage\n}\n\nfunc (r *R) Template() string {\n\treturn languageTemplate\n}\n\nfunc (r *R) Enabled() bool {\n\trRegex := `version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`\n\tr.extensions = []string{\"*.R\", \"*.Rmd\", \"*.Rsx\", \"*.Rda\", \"*.Rd\", \"*.Rproj\", \".Rproj.user\"}\n\tr.tooling = map[string]*cmd{\n\t\t\"Rscript\": {\n\t\t\texecutable: \"Rscript\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      rRegex,\n\t\t},\n\t\t\"R\": {\n\t\t\texecutable: \"R\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      rRegex,\n\t\t},\n\t\t\"R.exe\": {\n\t\t\texecutable: \"R.exe\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      rRegex,\n\t\t},\n\t}\n\tr.defaultTooling = []string{\"Rscript\", \"R\", \"R.exe\"}\n\tr.versionURLTemplate = \"https://www.r-project.org/\"\n\n\treturn r.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/r_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestR(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t\tHasRscript     bool\n\t\tHasR           bool\n\t\tHasRexe        bool\n\t}{\n\t\t{Case: \"Rscript 4.2.0\", ExpectedString: \"4.2.0\", HasRscript: true, Version: \"Rscript (R) version 4.2.0 (2022-04-22)\"},\n\t\t{Case: \"Rscript 4.1.3\", ExpectedString: \"4.1.3\", HasRscript: true, Version: \"R scripting front-end version 4.1.3 (2022-03-10)\"},\n\t\t{Case: \"Rscript 4.1.3 patched\", ExpectedString: \"4.1.3\", HasRscript: true, Version: \"R scripting front-end version 4.1.3 Patched (2022-03-10 r81896)\"},\n\t\t{Case: \"Rscript 4.0.0\", ExpectedString: \"4.0.0\", HasRscript: true, Version: \"R scripting front-end version 4.0.0 (2020-04-24)\"},\n\t\t{Case: \"Rscript devel\", ExpectedString: \"4.2.0\", HasRscript: true, Version: \"R scripting front-end version 4.2.0 Under development (unstable) (2022-03-14 r81896)\"},\n\n\t\t{Case: \"R 4.1.2\", ExpectedString: \"4.1.2\", HasR: true, Version: \"R version 4.1.2 (2021-11-01) -- \\\"Bird Hippie\\\"\"},\n\t\t{Case: \"R 4.1.3 patched\", ExpectedString: \"4.1.3\", HasR: true, Version: \"R version 4.1.3 Patched (2022-03-10 r81896) -- \\\"One Push-Up\\\"\"},\n\t\t{Case: \"R 4.0.0\", ExpectedString: \"4.0.0\", HasR: true, Version: \"R version 4.0.0 (2020-04-24) -- \\\"Arbor Day\\\"\"},\n\n\t\t{Case: \"R.exe 4.1.2\", ExpectedString: \"4.1.2\", HasRexe: true, Version: \"R version 4.1.2 (2021-11-01) -- \\\"Bird Hippie\\\"\"},\n\t\t{Case: \"R.exe 4.1.3 patched\", ExpectedString: \"4.1.3\", HasRexe: true, Version: \"R version 4.1.3 Patched (2022-03-10 r81896) -- \\\"One Push-Up\\\"\"},\n\t\t{Case: \"R.exe 4.0.0\", ExpectedString: \"4.0.0\", HasRexe: true, Version: \"R version 4.0.0 (2020-04-24) -- \\\"Arbor Day\\\"\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"R\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.R\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"HasCommand\", \"Rscript\").Return(tc.HasRscript)\n\t\tenv.On(\"RunCommand\", \"Rscript\", []string{\"--version\"}).Return(tc.Version, nil)\n\t\tenv.On(\"HasCommand\", \"R.exe\").Return(tc.HasRexe)\n\t\tenv.On(\"RunCommand\", \"R.exe\", []string{\"--version\"}).Return(tc.Version, nil)\n\n\t\tr := &R{}\n\t\tr.Init(props, env)\n\n\t\tassert.True(t, r.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, r.Template(), r), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/ramadan.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// errNotRamadan is returned by setData when the segment is disabled because\n// it is not Ramadan and hide_outside_ramadan is true. It is not logged as an error.\nvar errNotRamadan = errors.New(\"not in Ramadan\")\n\n// Ramadan displays Sehar (Fajr) and Iftar (Maghrib) prayer timings\n// along with a countdown to the next event during Ramadan.\ntype Ramadan struct {\n\tBase\n\tFajr          string\n\tIftar         string\n\tImsak         string\n\tNextEvent     string\n\tTimeRemaining string\n\tRozaNumber    int\n\tFasting       bool\n}\n\nconst (\n\t// RamadanLatitude is the latitude used for prayer time calculation.\n\tRamadanLatitude options.Option = \"latitude\"\n\t// RamadanLongitude is the longitude used for prayer time calculation.\n\tRamadanLongitude options.Option = \"longitude\"\n\t// RamadanCity is the city used for prayer time lookup.\n\tRamadanCity options.Option = \"city\"\n\t// RamadanCountry is the country used with city for prayer time lookup.\n\tRamadanCountry options.Option = \"country\"\n\t// RamadanMethod is the prayer calculation method (0-23, default 3 = Muslim World League).\n\tRamadanMethod options.Option = \"method\"\n\t// RamadanSchool is the madhab school (0=Shafi, 1=Hanafi).\n\tRamadanSchool options.Option = \"school\"\n\t// RamadanHideOutside hides the segment when not in Ramadan.\n\tRamadanHideOutside options.Option = \"hide_outside_ramadan\"\n\t// RamadanFirstRozaDate allows overriding the first day of Ramadan for local moon sighting.\n\tRamadanFirstRozaDate options.Option = \"first_roza_date\"\n)\n\ntype ramadanTimings struct {\n\tFajr    string `json:\"Fajr\"`\n\tImsak   string `json:\"Imsak\"`\n\tMaghrib string `json:\"Maghrib\"`\n}\n\ntype ramadanHijriMonth struct {\n\tNumber int `json:\"number\"`\n}\n\ntype ramadanHijriDate struct {\n\tDay   string            `json:\"day\"`\n\tMonth ramadanHijriMonth `json:\"month\"`\n}\n\ntype ramadanDate struct {\n\tHijri ramadanHijriDate `json:\"hijri\"`\n}\n\ntype ramadanData struct {\n\tTimings ramadanTimings `json:\"timings\"`\n\tDate    ramadanDate    `json:\"date\"`\n}\n\ntype ramadanResponse struct {\n\tData ramadanData `json:\"data\"`\n}\n\nfunc (r *Ramadan) Template() string {\n\treturn \" \\U0001F319 Roza {{.RozaNumber}} \\u00b7 {{.NextEvent}} in {{.TimeRemaining}} \"\n}\n\nfunc (r *Ramadan) Enabled() bool {\n\terr := r.setData()\n\tif err != nil {\n\t\tif !errors.Is(err, errNotRamadan) {\n\t\t\tlog.Error(err)\n\t\t}\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (r *Ramadan) setData() error {\n\tnow := time.Now()\n\tdate := now.Format(\"02-01-2006\")\n\n\tapiURL, err := r.buildURL(date)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\thttpTimeout := r.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tbody, err := r.env.HTTPRequest(apiURL, nil, httpTimeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar response ramadanResponse\n\tif err = json.Unmarshal(body, &response); err != nil {\n\t\treturn err\n\t}\n\n\tdata := response.Data\n\n\t// Determine if we are currently in Ramadan and compute the roza number.\n\tfirstRozaStr := r.options.String(RamadanFirstRozaDate, \"\")\n\thideOutside := r.options.Bool(RamadanHideOutside, true)\n\n\tinRamadan, rozaNumber := r.resolveRamadanDay(now, data, firstRozaStr)\n\n\tif !inRamadan && hideOutside {\n\t\treturn errNotRamadan\n\t}\n\n\tif inRamadan {\n\t\tr.RozaNumber = rozaNumber\n\t}\n\n\tfajrTime, err := parseEventTime(now, data.Timings.Fajr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse Fajr time: %w\", err)\n\t}\n\n\tiftarTime, err := parseEventTime(now, data.Timings.Maghrib)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse Iftar time: %w\", err)\n\t}\n\n\timsakTime, err := parseEventTime(now, data.Timings.Imsak)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse Imsak time: %w\", err)\n\t}\n\n\tr.Fajr = fajrTime.Format(\"15:04\")\n\tr.Iftar = iftarTime.Format(\"15:04\")\n\tr.Imsak = imsakTime.Format(\"15:04\")\n\n\t// When past Iftar, fetch tomorrow's Fajr from the API for a DST-accurate countdown.\n\t// Falls back to the same wall-clock time on the next calendar day if the fetch fails.\n\tvar tomorrowFajr time.Time\n\tif !now.Before(iftarTime) {\n\t\ttomorrow := now.AddDate(0, 0, 1)\n\t\tvar fetchErr error\n\t\ttomorrowFajr, fetchErr = r.fetchFajrTime(tomorrow)\n\t\tif fetchErr != nil {\n\t\t\ttomorrowFajr = time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(),\n\t\t\t\tfajrTime.Hour(), fajrTime.Minute(), 0, 0, fajrTime.Location())\n\t\t}\n\t}\n\n\tr.computeNextEvent(now, fajrTime, iftarTime, tomorrowFajr)\n\n\treturn nil\n}\n\n// computeNextEvent sets NextEvent, TimeRemaining, and Fasting based on the current time\n// relative to today's Fajr and Iftar times. tomorrowFajrTime must be populated by the\n// caller when now is past Iftar; it is ignored otherwise.\nfunc (r *Ramadan) computeNextEvent(now, fajrTime, iftarTime, tomorrowFajrTime time.Time) {\n\tr.Fasting = !now.Before(fajrTime) && now.Before(iftarTime)\n\n\tif now.Before(fajrTime) {\n\t\tr.NextEvent = \"Sehar\"\n\t\tr.TimeRemaining = formatDuration(fajrTime.Sub(now))\n\t\treturn\n\t}\n\n\tif now.Before(iftarTime) {\n\t\tr.NextEvent = \"Iftar\"\n\t\tr.TimeRemaining = formatDuration(iftarTime.Sub(now))\n\t\treturn\n\t}\n\n\t// After Iftar — use tomorrow's Fajr time fetched from the API (or an AddDate fallback).\n\tr.NextEvent = \"Sehar\"\n\tr.TimeRemaining = formatDuration(tomorrowFajrTime.Sub(now))\n}\n\n// fetchFajrTime fetches the Fajr time for the given date from the Aladhan API.\nfunc (r *Ramadan) fetchFajrTime(date time.Time) (time.Time, error) {\n\tdateStr := date.Format(\"02-01-2006\")\n\n\tapiURL, err := r.buildURL(dateStr)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\n\thttpTimeout := r.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tbody, err := r.env.HTTPRequest(apiURL, nil, httpTimeout)\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\n\tvar response ramadanResponse\n\tif err = json.Unmarshal(body, &response); err != nil {\n\t\treturn time.Time{}, err\n\t}\n\n\treturn parseEventTime(date, response.Data.Timings.Fajr)\n}\n\n// buildURL constructs the Aladhan API URL for today's prayer timings.\n// City+country takes precedence over lat/lng when both are provided.\nfunc (r *Ramadan) buildURL(date string) (string, error) {\n\tmethod := r.options.Int(RamadanMethod, 3)\n\tschool := r.options.Int(RamadanSchool, 0)\n\n\tcity := r.options.String(RamadanCity, \"\")\n\tcountry := r.options.String(RamadanCountry, \"\")\n\n\tif city != \"\" && country != \"\" {\n\t\treturn fmt.Sprintf(\n\t\t\t\"https://api.aladhan.com/v1/timingsByCity/%s?city=%s&country=%s&method=%d&school=%d\",\n\t\t\tdate,\n\t\t\turl.QueryEscape(city),\n\t\t\turl.QueryEscape(country),\n\t\t\tmethod,\n\t\t\tschool,\n\t\t), nil\n\t}\n\n\tif r.options.Any(RamadanLatitude, nil) == nil || r.options.Any(RamadanLongitude, nil) == nil {\n\t\treturn \"\", errors.New(\"no location configured: set city+country or latitude+longitude\")\n\t}\n\n\tlat := r.options.Float64(RamadanLatitude, 0)\n\tlng := r.options.Float64(RamadanLongitude, 0)\n\n\treturn fmt.Sprintf(\n\t\t\"https://api.aladhan.com/v1/timings/%s?latitude=%g&longitude=%g&method=%d&school=%d\",\n\t\tdate, lat, lng, method, school,\n\t), nil\n}\n\n// resolveRamadanDay returns whether today is in Ramadan and the roza (day) number.\n// When first_roza_date is set it overrides the API's Hijri month detection.\nfunc (r *Ramadan) resolveRamadanDay(now time.Time, data ramadanData, firstRozaStr string) (bool, int) {\n\tif firstRozaStr != \"\" {\n\t\tfirstRoza, err := time.ParseInLocation(\"2006-01-02\", firstRozaStr, now.Location())\n\t\tif err == nil {\n\t\t\t// Use UTC noon arithmetic to avoid DST off-by-one errors.\n\t\t\tny, nm, nd := now.Date()\n\t\t\tfy, fm, fd := firstRoza.Date()\n\t\t\tnowDay := time.Date(ny, nm, nd, 12, 0, 0, 0, time.UTC)\n\t\t\tfirstDay := time.Date(fy, fm, fd, 12, 0, 0, 0, time.UTC)\n\n\t\t\tdaysSince := int(nowDay.Sub(firstDay).Hours() / 24)\n\t\t\tif daysSince >= 0 && daysSince < 30 {\n\t\t\t\treturn true, daysSince + 1\n\t\t\t}\n\n\t\t\treturn false, 0\n\t\t}\n\t\t// Parse error: fall through to API-based Hijri month detection.\n\t}\n\n\tif data.Date.Hijri.Month.Number != 9 {\n\t\treturn false, 0\n\t}\n\n\trozaNumber := 0\n\tif _, err := fmt.Sscanf(data.Date.Hijri.Day, \"%d\", &rozaNumber); err != nil {\n\t\treturn false, 0\n\t}\n\n\treturn true, rozaNumber\n}\n\n// parseEventTime combines today's date with an HH:MM time string from the API.\nfunc parseEventTime(now time.Time, hhmm string) (time.Time, error) {\n\t// The API may return timezone-suffixed values like \"05:23 (PKT)\"; strip any suffix.\n\ttimeStr := hhmm\n\tif len(timeStr) > 5 {\n\t\ttimeStr = timeStr[:5]\n\t}\n\n\tparsed, err := time.ParseInLocation(\"15:04\", timeStr, now.Location())\n\tif err != nil {\n\t\treturn time.Time{}, err\n\t}\n\n\treturn time.Date(now.Year(), now.Month(), now.Day(), parsed.Hour(), parsed.Minute(), 0, 0, now.Location()), nil\n}\n\n// formatDuration formats a duration as \"Xh Ym\" or \"Ym\" when less than an hour.\nfunc formatDuration(d time.Duration) string {\n\tif d < 0 {\n\t\td = 0\n\t}\n\n\ttotalMinutes := int(d.Minutes())\n\th := totalMinutes / 60\n\tm := totalMinutes % 60\n\n\tif h > 0 {\n\t\treturn fmt.Sprintf(\"%dh %dm\", h, m)\n\t}\n\n\treturn fmt.Sprintf(\"%dm\", m)\n}\n"
  },
  {
    "path": "src/segments/ramadan_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\tlibtime \"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst ramadanTestResponse = `{\n  \"code\": 200,\n  \"status\": \"OK\",\n  \"data\": {\n    \"timings\": {\n      \"Fajr\": \"05:15\",\n      \"Imsak\": \"05:05\",\n      \"Maghrib\": \"18:30\"\n    },\n    \"date\": {\n      \"hijri\": {\n        \"day\": \"5\",\n        \"month\": { \"number\": 9 }\n      }\n    }\n  }\n}`\n\nconst ramadanNonRamadanResponse = `{\n  \"code\": 200,\n  \"status\": \"OK\",\n  \"data\": {\n    \"timings\": {\n      \"Fajr\": \"05:15\",\n      \"Imsak\": \"05:05\",\n      \"Maghrib\": \"18:30\"\n    },\n    \"date\": {\n      \"hijri\": {\n        \"day\": \"10\",\n        \"month\": { \"number\": 7 }\n      }\n    }\n  }\n}`\n\nfunc TestRamadanSegment(t *testing.T) {\n\ttoday := libtime.Now()\n\tdate := today.Format(\"02-01-2006\")\n\t// firstRoza 5 days before today so roza number is always 6 regardless of when tests run\n\tfirstRoza := today.AddDate(0, 0, -5).Format(\"2006-01-02\")\n\n\tcases := []struct {\n\t\tAPIError        error\n\t\tProps           options.Map\n\t\tCase            string\n\t\tAPIResponse     string\n\t\tExpectedRoza    int\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:        \"in Ramadan via API hijri month\",\n\t\t\tAPIResponse: ramadanTestResponse,\n\t\t\tProps: options.Map{\n\t\t\t\tRamadanLatitude:  51.5,\n\t\t\t\tRamadanLongitude: -0.1,\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedRoza:    5,\n\t\t},\n\t\t{\n\t\t\tCase:        \"in Ramadan via first_roza_date override\",\n\t\t\tAPIResponse: ramadanNonRamadanResponse,\n\t\t\tProps: options.Map{\n\t\t\t\tRamadanCity:          \"Lahore\",\n\t\t\t\tRamadanCountry:       \"Pakistan\",\n\t\t\t\tRamadanFirstRozaDate: firstRoza,\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedRoza:    6,\n\t\t},\n\t\t{\n\t\t\tCase:        \"not in Ramadan, hide=true (default)\",\n\t\t\tAPIResponse: ramadanNonRamadanResponse,\n\t\t\tProps: options.Map{\n\t\t\t\tRamadanLatitude:  51.5,\n\t\t\t\tRamadanLongitude: -0.1,\n\t\t\t},\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:        \"not in Ramadan, hide=false shows segment\",\n\t\t\tAPIResponse: ramadanNonRamadanResponse,\n\t\t\tProps: options.Map{\n\t\t\t\tRamadanLatitude:    51.5,\n\t\t\t\tRamadanLongitude:   -0.1,\n\t\t\t\tRamadanHideOutside: false,\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedRoza:    0,\n\t\t},\n\t\t{\n\t\t\tCase:        \"API error returns false\",\n\t\t\tAPIResponse: \"\",\n\t\t\tAPIError:    errors.New(\"network error\"),\n\t\t\tProps: options.Map{\n\t\t\t\tRamadanLatitude:  51.5,\n\t\t\t\tRamadanLongitude: -0.1,\n\t\t\t},\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no location configured returns false\",\n\t\t\tAPIResponse:     ramadanTestResponse,\n\t\t\tProps:           options.Map{},\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\ttomorrow := today.AddDate(0, 0, 1)\n\ttomorrowDate := tomorrow.Format(\"02-01-2006\")\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\n\t\t// Build the expected URL based on props to pass to the mock\n\t\tcity, hasCity := tc.Props[RamadanCity]\n\t\tcountry, hasCountry := tc.Props[RamadanCountry]\n\t\t_, hasLat := tc.Props[RamadanLatitude]\n\t\t_, hasLng := tc.Props[RamadanLongitude]\n\n\t\tvar apiURL string\n\t\tvar tomorrowAPIURL string\n\n\t\tswitch {\n\t\tcase hasCity && hasCountry:\n\t\t\tapiURL = \"https://api.aladhan.com/v1/timingsByCity/\" + date +\n\t\t\t\t\"?city=\" + city.(string) + \"&country=\" + country.(string) + \"&method=3&school=0\"\n\t\t\ttomorrowAPIURL = \"https://api.aladhan.com/v1/timingsByCity/\" + tomorrowDate +\n\t\t\t\t\"?city=\" + city.(string) + \"&country=\" + country.(string) + \"&method=3&school=0\"\n\t\tcase hasLat && hasLng:\n\t\t\tapiURL = \"https://api.aladhan.com/v1/timings/\" + date +\n\t\t\t\t\"?latitude=51.5&longitude=-0.1&method=3&school=0\"\n\t\t\ttomorrowAPIURL = \"https://api.aladhan.com/v1/timings/\" + tomorrowDate +\n\t\t\t\t\"?latitude=51.5&longitude=-0.1&method=3&school=0\"\n\t\t}\n\n\t\tif apiURL != \"\" {\n\t\t\tenv.On(\"HTTPRequest\", apiURL).Return([]byte(tc.APIResponse), tc.APIError)\n\t\t}\n\n\t\t// Also mock tomorrow's URL (called after Iftar for the next Sehar countdown).\n\t\t// Marked as Maybe() so the test passes regardless of what time of day it runs.\n\t\tif tomorrowAPIURL != \"\" {\n\t\t\tenv.On(\"HTTPRequest\", tomorrowAPIURL).Maybe().Return([]byte(tc.APIResponse), nil)\n\t\t}\n\n\t\tr := &Ramadan{}\n\t\tr.Init(tc.Props, env)\n\n\t\tenabled := r.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedRoza, r.RozaNumber, tc.Case)\n\t}\n}\n\nfunc TestComputeNextEvent(t *testing.T) {\n\tbase := libtime.Date(2026, 3, 1, 0, 0, 0, 0, libtime.UTC)\n\tfajr := base.Add(5*libtime.Hour + 15*libtime.Minute)\n\tiftar := base.Add(18*libtime.Hour + 30*libtime.Minute)\n\tnextDay := fajr.AddDate(0, 0, 1)\n\ttomorrowFajr := libtime.Date(nextDay.Year(), nextDay.Month(), nextDay.Day(), fajr.Hour(), fajr.Minute(), 0, 0, fajr.Location())\n\n\tcases := []struct {\n\t\tNow               libtime.Time\n\t\tCase              string\n\t\tExpectedNextEvent string\n\t\tExpectedFasting   bool\n\t}{\n\t\t{Case: \"before fajr\", Now: fajr.Add(-10 * libtime.Minute), ExpectedFasting: false, ExpectedNextEvent: \"Sehar\"},\n\t\t{Case: \"exactly at fajr (boundary)\", Now: fajr, ExpectedFasting: true, ExpectedNextEvent: \"Iftar\"},\n\t\t{Case: \"after fajr, before iftar\", Now: fajr.Add(1 * libtime.Hour), ExpectedFasting: true, ExpectedNextEvent: \"Iftar\"},\n\t\t{Case: \"exactly at iftar\", Now: iftar, ExpectedFasting: false, ExpectedNextEvent: \"Sehar\"},\n\t\t{Case: \"after iftar\", Now: iftar.Add(30 * libtime.Minute), ExpectedFasting: false, ExpectedNextEvent: \"Sehar\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tr := &Ramadan{}\n\t\tr.computeNextEvent(tc.Now, fajr, iftar, tomorrowFajr)\n\t\tassert.Equal(t, tc.ExpectedFasting, r.Fasting, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedNextEvent, r.NextEvent, tc.Case)\n\t}\n}\n\nfunc TestFormatDuration(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tInput    libtime.Duration\n\t}{\n\t\t{\"hours and minutes\", \"3h 42m\", 3*libtime.Hour + 42*libtime.Minute},\n\t\t{\"minutes only\", \"25m\", 25 * libtime.Minute},\n\t\t{\"zero\", \"0m\", 0},\n\t\t{\"negative clamped to zero\", \"0m\", -5 * libtime.Minute},\n\t\t{\"exact hour\", \"1h 0m\", libtime.Hour},\n\t}\n\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, formatDuration(tc.Input), tc.Case)\n\t}\n}\n\nfunc TestParseEventTime(t *testing.T) {\n\tnow := libtime.Date(2026, 2, 24, 12, 0, 0, 0, libtime.UTC)\n\n\tcases := []struct {\n\t\tCase           string\n\t\tInput          string\n\t\tExpectedHour   int\n\t\tExpectedMinute int\n\t}{\n\t\t{\"plain HH:MM\", \"05:23\", 5, 23},\n\t\t{\"with timezone suffix\", \"05:23 (PKT)\", 5, 23},\n\t\t{\"midnight\", \"00:04\", 0, 4},\n\t}\n\n\tfor _, tc := range cases {\n\t\tresult, err := parseEventTime(now, tc.Input)\n\t\tassert.NoError(t, err, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedHour, result.Hour(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedMinute, result.Minute(), tc.Case)\n\t\tassert.Equal(t, 2026, result.Year(), tc.Case)\n\t}\n}\n\nfunc TestResolveRamadanDay(t *testing.T) {\n\tnow := libtime.Date(2026, 2, 24, 12, 0, 0, 0, libtime.UTC)\n\tr := &Ramadan{}\n\n\tramadanData := ramadanData{\n\t\tDate: ramadanDate{\n\t\t\tHijri: ramadanHijriDate{\n\t\t\t\tDay:   \"5\",\n\t\t\t\tMonth: ramadanHijriMonth{Number: 9},\n\t\t\t},\n\t\t},\n\t}\n\tnonRamadanData := ramadanData\n\tnonRamadanData.Date.Hijri.Month.Number = 7\n\n\t// via hijri month\n\tinRamadan, roza := r.resolveRamadanDay(now, ramadanData, \"\")\n\tassert.True(t, inRamadan)\n\tassert.Equal(t, 5, roza)\n\n\t// not Ramadan month\n\tinRamadan, roza = r.resolveRamadanDay(now, nonRamadanData, \"\")\n\tassert.False(t, inRamadan)\n\tassert.Equal(t, 0, roza)\n\n\t// first_roza_date override — today is day 6 (2026-02-24, first roza 2026-02-19)\n\tinRamadan, roza = r.resolveRamadanDay(now, nonRamadanData, \"2026-02-19\")\n\tassert.True(t, inRamadan)\n\tassert.Equal(t, 6, roza)\n\n\t// first_roza_date override — date before start\n\tbeforeStart := libtime.Date(2026, 2, 18, 12, 0, 0, 0, libtime.UTC)\n\tinRamadan, _ = r.resolveRamadanDay(beforeStart, nonRamadanData, \"2026-02-19\")\n\tassert.False(t, inRamadan)\n\n\t// first_roza_date override — past 30 days\n\tafterEnd := libtime.Date(2026, 3, 22, 12, 0, 0, 0, libtime.UTC)\n\tinRamadan, _ = r.resolveRamadanDay(afterEnd, nonRamadanData, \"2026-02-19\")\n\tassert.False(t, inRamadan)\n}\n\nfunc TestRamadanComputeNextEvent(t *testing.T) {\n\tfajr := libtime.Date(2026, 3, 10, 5, 15, 0, 0, libtime.UTC)\n\tiftar := libtime.Date(2026, 3, 10, 18, 30, 0, 0, libtime.UTC)\n\n\tcases := []struct {\n\t\tCase              string\n\t\tNow               libtime.Time\n\t\tExpectedNextEvent string\n\t\tExpectedFasting   bool\n\t}{\n\t\t{\n\t\t\tCase:              \"before Fajr\",\n\t\t\tNow:               libtime.Date(2026, 3, 10, 4, 0, 0, 0, libtime.UTC),\n\t\t\tExpectedNextEvent: \"Sehar\",\n\t\t\tExpectedFasting:   false,\n\t\t},\n\t\t{\n\t\t\tCase:              \"during fasting window\",\n\t\t\tNow:               libtime.Date(2026, 3, 10, 12, 0, 0, 0, libtime.UTC),\n\t\t\tExpectedNextEvent: \"Iftar\",\n\t\t\tExpectedFasting:   true,\n\t\t},\n\t\t{\n\t\t\tCase:              \"after Iftar\",\n\t\t\tNow:               libtime.Date(2026, 3, 10, 20, 0, 0, 0, libtime.UTC),\n\t\t\tExpectedNextEvent: \"Sehar\",\n\t\t\tExpectedFasting:   false,\n\t\t},\n\t}\n\n\tnextDay := fajr.AddDate(0, 0, 1)\n\ttomorrowFajr := libtime.Date(nextDay.Year(), nextDay.Month(), nextDay.Day(), fajr.Hour(), fajr.Minute(), 0, 0, fajr.Location())\n\n\tfor _, tc := range cases {\n\t\tr := &Ramadan{}\n\t\tr.computeNextEvent(tc.Now, fajr, iftar, tomorrowFajr)\n\t\tassert.Equal(t, tc.ExpectedNextEvent, r.NextEvent, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedFasting, r.Fasting, tc.Case)\n\t\tassert.NotEmpty(t, r.TimeRemaining, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/react.go",
    "content": "package segments\n\ntype React struct {\n\tLanguage\n}\n\nfunc (r *React) Template() string {\n\treturn languageTemplate\n}\n\nfunc (r *React) Enabled() bool {\n\tr.extensions = []string{\"package.json\"}\n\tr.tooling = map[string]*cmd{\n\t\t\"react\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\tgetVersion: r.getVersion,\n\t\t},\n\t}\n\tr.defaultTooling = []string{\"react\"}\n\tr.versionURLTemplate = \"https://github.com/facebook/react/releases/tag/v{{.Full}}\"\n\n\tif !r.hasNodePackage(\"react\") {\n\t\treturn false\n\t}\n\n\treturn r.Language.Enabled()\n}\n\nfunc (r *React) getVersion() (string, error) {\n\treturn r.nodePackageVersion(\"react\")\n}\n"
  },
  {
    "path": "src/segments/root.go",
    "content": "package segments\n\ntype Root struct {\n\tBase\n}\n\nfunc (rt *Root) Template() string {\n\treturn \" \\uF0E7 \"\n}\n\nfunc (rt *Root) Enabled() bool {\n\treturn rt.env.Root()\n}\n"
  },
  {
    "path": "src/segments/ruby.go",
    "content": "package segments\n\ntype Ruby struct {\n\tLanguage\n}\n\nfunc (r *Ruby) Template() string {\n\treturn languageTemplate\n}\n\nfunc (r *Ruby) Enabled() bool {\n\tr.extensions = []string{\"*.rb\", \"Rakefile\", \"Gemfile\"}\n\tr.tooling = map[string]*cmd{\n\t\t\"rbenv\": {\n\t\t\texecutable: \"rbenv\",\n\t\t\targs:       []string{\"version-name\"},\n\t\t\tregex:      `(?P<version>.+)`,\n\t\t},\n\t\t\"rvm-prompt\": {\n\t\t\texecutable: \"rvm-prompt\",\n\t\t\targs:       []string{\"i\", \"v\", \"g\"},\n\t\t\tregex:      `(?P<version>.+)`,\n\t\t},\n\t\t\"chruby\": {\n\t\t\texecutable: \"chruby\",\n\t\t\targs:       []string(nil),\n\t\t\tregex:      `\\* (?P<version>.+)\\n`,\n\t\t},\n\t\t\"asdf\": {\n\t\t\texecutable: \"asdf\",\n\t\t\targs:       []string{\"current\", \"ruby\"},\n\t\t\tregex:      `ruby\\s+(?P<version>[^\\s]+)\\s+`,\n\t\t},\n\t\t\"ruby\": {\n\t\t\texecutable: \"ruby\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `ruby\\s+(?P<version>[^\\s]+)\\s+`,\n\t\t},\n\t}\n\tr.defaultTooling = []string{\"rbenv\", \"rvm-prompt\", \"chruby\", \"asdf\", \"ruby\"}\n\n\tenabled := r.Language.Enabled()\n\n\t// this happens when no version is set\n\tif r.Full == \"______\" {\n\t\tr.Full = \"\"\n\t}\n\n\treturn enabled\n}\n"
  },
  {
    "path": "src/segments/ruby_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRuby(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t\tHasRbenv       bool\n\t\tHasRvmprompt   bool\n\t\tHasChruby      bool\n\t\tHasAsdf        bool\n\t\tHasRuby        bool\n\t\tHasRubyFiles   bool\n\t\tHasRakeFile    bool\n\t\tHasGemFile     bool\n\t\tFetchVersion   bool\n\t}{\n\t\t{Case: \"Ruby files\", ExpectedString: \"\", FetchVersion: false, HasRubyFiles: true},\n\t\t{Case: \"Rakefile\", ExpectedString: \"\", FetchVersion: false, HasRakeFile: true},\n\t\t{Case: \"Gemfile\", ExpectedString: \"\", FetchVersion: false, HasGemFile: true},\n\t\t{Case: \"Gemfile with version\", ExpectedString: \"err parsing info from ruby with\", FetchVersion: true, HasGemFile: true},\n\t\t{\n\t\t\tCase:           \"Version with chruby\",\n\t\t\tExpectedString: \"ruby-2.6.3\",\n\t\t\tFetchVersion:   true,\n\t\t\tHasRubyFiles:   true,\n\t\t\tHasChruby:      true,\n\t\t\tVersion: ` * ruby-2.6.3\n\t\t\truby-1.9.3-p392\n\t\t\tjruby-1.7.0\n\t\t\trubinius-2.0.0-rc1`,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Version with chruby line 2\",\n\t\t\tExpectedString: \"ruby-1.9.3-p392\",\n\t\t\tFetchVersion:   true,\n\t\t\tHasRubyFiles:   true,\n\t\t\tHasChruby:      true,\n\t\t\tVersion: ` ruby-2.6.3\n\t\t\t* ruby-1.9.3-p392\n\t\t\tjruby-1.7.0\n\t\t\trubinius-2.0.0-rc1`,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Version with asdf\",\n\t\t\tExpectedString: \"2.6.3\",\n\t\t\tFetchVersion:   true,\n\t\t\tHasRubyFiles:   true,\n\t\t\tHasAsdf:        true,\n\t\t\tVersion:        \"ruby            2.6.3           /Users/jan/Projects/oh-my-posh/.tool-versions\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Version with asdf not set\",\n\t\t\tExpectedString: \"\",\n\t\t\tFetchVersion:   true,\n\t\t\tHasRubyFiles:   true,\n\t\t\tHasAsdf:        true,\n\t\t\tVersion:        \"ruby            ______          No version set. Run \\\"asdf <global|shell|local> ruby <version>\\\"\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Version with ruby\",\n\t\t\tExpectedString: \"2.6.3\",\n\t\t\tFetchVersion:   true,\n\t\t\tHasRubyFiles:   true,\n\t\t\tHasRuby:        true,\n\t\t\tVersion:        \"ruby  2.6.3 (2019-04-16 revision 67580) [universal.x86_64-darwin20]\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"ruby\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.rb\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tenv.On(\"HasCommand\", \"rbenv\").Return(tc.HasRbenv)\n\t\tenv.On(\"RunCommand\", \"rbenv\", []string{\"version-name\"}).Return(tc.Version, nil)\n\t\tenv.On(\"HasCommand\", \"rvm-prompt\").Return(tc.HasRvmprompt)\n\t\tenv.On(\"RunCommand\", \"rvm-prompt\", []string{\"i\", \"v\", \"g\"}).Return(tc.Version, nil)\n\t\tenv.On(\"HasCommand\", \"chruby\").Return(tc.HasChruby)\n\t\tenv.On(\"RunCommand\", \"chruby\", []string(nil)).Return(tc.Version, nil)\n\t\tenv.On(\"HasCommand\", \"asdf\").Return(tc.HasAsdf)\n\t\tenv.On(\"RunCommand\", \"asdf\", []string{\"current\", \"ruby\"}).Return(tc.Version, nil)\n\t\tenv.On(\"HasFiles\", \"Rakefile\").Return(tc.HasRakeFile)\n\t\tenv.On(\"HasFiles\", \"Gemfile\").Return(tc.HasGemFile)\n\n\t\tprops[options.FetchVersion] = tc.FetchVersion\n\n\t\truby := &Ruby{}\n\t\truby.Init(props, env)\n\n\t\tassert.True(t, ruby.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, ruby.Template(), ruby), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/rust.go",
    "content": "package segments\n\ntype Rust struct {\n\tLanguage\n}\n\nfunc (r *Rust) Template() string {\n\treturn languageTemplate\n}\n\nfunc (r *Rust) Enabled() bool {\n\tr.extensions = []string{\"*.rs\", \"Cargo.toml\", \"Cargo.lock\"}\n\tr.tooling = map[string]*cmd{\n\t\t\"rustc\": {\n\t\t\texecutable: \"rustc\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(rust version|rustc) (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))(-(?P<prerelease>[a-z]+))?)(( \\((?P<buildmetadata>[0-9a-f]+ [0-9]+-[0-9]+-[0-9]+)\\))?)`, //nolint:lll\n\t\t},\n\t}\n\tr.defaultTooling = []string{\"rustc\"}\n\n\treturn r.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/rust_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRust(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Rust 1.64.0\", ExpectedString: \"1.64.0\", Version: \"rustc 1.64.0\"},\n\t\t{Case: \"Rust 1.53.0\", ExpectedString: \"1.53.0\", Version: \"rustc 1.53.0 (4369396ce 2021-04-27)\"},\n\t\t{Case: \"Rust 1.66.0\", ExpectedString: \"1.66.0-nightly\", Version: \"rustc 1.66.0-nightly (01af5040f 2022-10-04)\"},\n\t\t{\n\t\t\tCase:           \"Toolchain not installed\",\n\t\t\tExpectedString: \"1.81.0\",\n\t\t\tVersion: ` info: syncing channel updates for '1.81.0-x86_64-pc-windows-msvc'\n    info: latest update on 2024-09-05, rust version 1.81.0 (eeb90cda1 2024-09-04)\n    info: downloading component 'cargo'\n    info: downloading component 'clippy'\n    info: downloading component 'rust-analyzer'\n    info: downloading component 'rust-src'\n    info: downloading component 'rust-std'\n    info: downloading component 'rustc'\n    info: downloading component 'rustfmt'\n    info: installing component 'cargo'\n    info: installing component 'clippy'\n    info: installing component 'rust-analyzer'\n    info: installing component 'rust-src'\n    info: installing component 'rust-std'\n    info: installing component 'rustc'`,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"rustc\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.rs\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tr := &Rust{}\n\t\tr.Init(props, env)\n\t\tassert.True(t, r.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, r.Template(), r), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/sapling.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\n// SaplingStatus represents part of the status of a Sapling repository\ntype SaplingStatus struct {\n\tScmStatus\n}\n\nfunc (s *SaplingStatus) add(code string) {\n\t// M = modified\n\t// A = added\n\t// R = removed/deleted\n\t// C = clean\n\t// ! = missing (deleted by a non-sl command, but still tracked)\n\t// ? = not tracked\n\t// I = ignored\n\t//   = origin of the previous file (with --copies)\n\tswitch code {\n\tcase \"M\":\n\t\ts.Modified++\n\tcase \"A\":\n\t\ts.Added++\n\tcase \"R\":\n\t\ts.Deleted++\n\tcase \"C\":\n\t\ts.Clean++\n\tcase \"!\":\n\t\ts.Missing++\n\tcase \"?\":\n\t\ts.Untracked++\n\tcase \"I\":\n\t\ts.Ignored++\n\t}\n}\n\nconst (\n\tSAPLINGCOMMAND   = \"sl\"\n\tSLCOMMITTEMPLATE = \"no:{node}\\nns:{sl_node}\\nnd:{sl_date}\\nun:{sl_user}\\nbm:{activebookmark}\\ndn:{desc|firstline}\"\n)\n\ntype Sapling struct {\n\tWorking     *SaplingStatus\n\tShortHash   string\n\tHash        string\n\tWhen        string\n\tAuthor      string\n\tBookmark    string\n\tDescription string\n\tScm\n\tNew bool\n}\n\nfunc (sl *Sapling) Template() string {\n\treturn \" {{ if .Bookmark }}\\uf097 {{ .Bookmark }}*{{ else }}\\ue729 {{ .ShortHash }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }} \"\n}\n\nfunc (sl *Sapling) Enabled() bool {\n\tif !sl.shouldDisplay() {\n\t\treturn false\n\t}\n\n\tsl.setHeadContext()\n\n\treturn true\n}\n\nfunc (sl *Sapling) shouldDisplay() bool {\n\tsl.command = SAPLINGCOMMAND\n\n\tif !sl.hasCommand(SAPLINGCOMMAND) {\n\t\treturn false\n\t}\n\n\tslDir, err := sl.env.HasParentFilePath(\".sl\", false)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tsl.mainSCMDir = slDir.Path\n\tsl.scmDir = slDir.Path\n\t// convert the worktree file path to a windows one when in a WSL shared folder\n\tsl.repoRootDir = strings.TrimSuffix(sl.convertToWindowsPath(slDir.Path), \"/.sl\")\n\tsl.RepoName = path.Base(sl.convertToLinuxPath(sl.repoRootDir))\n\tsl.setDir(slDir.Path)\n\n\treturn true\n}\n\nfunc (sl *Sapling) CacheKey() (string, bool) {\n\tdir, err := sl.env.HasParentFilePath(\".sl\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn dir.Path, true\n}\n\nfunc (sl *Sapling) setDir(dir string) {\n\tdir = path.ReplaceHomeDirPrefixWithTilde(dir) // align with template PWD\n\n\tif sl.env.GOOS() == runtime.WINDOWS {\n\t\tsl.Dir = strings.TrimSuffix(dir, `\\.sl`)\n\t\treturn\n\t}\n\n\tsl.Dir = strings.TrimSuffix(dir, \"/.sl\")\n}\n\nfunc (sl *Sapling) setHeadContext() {\n\tsl.setCommitContext()\n\n\tstatusFormats := sl.options.KeyValueMap(StatusFormats, map[string]string{})\n\tsl.Working = &SaplingStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\tdisplayStatus := sl.options.Bool(FetchStatus, true)\n\tif !displayStatus {\n\t\treturn\n\t}\n\n\tchanges := sl.getSaplingCommandOutput(\"status\")\n\tif changes == \"\" {\n\t\treturn\n\t}\n\tlines := strings.SplitSeq(changes, \"\\n\")\n\tfor line := range lines {\n\t\tline = strings.TrimSpace(line)\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\t// element is the element from someSlice for where we are\n\t\tsl.Working.add(line[0:1])\n\t}\n}\n\nfunc (sl *Sapling) setCommitContext() {\n\tbody := sl.getSaplingCommandOutput(\"log\", \"--limit\", \"1\", \"--template\", SLCOMMITTEMPLATE)\n\tif body == \"\" {\n\t\tsl.New = true\n\t\treturn\n\t}\n\tsplitted := strings.SplitSeq(strings.TrimSpace(body), \"\\n\")\n\tfor line := range splitted {\n\t\tline = strings.TrimSpace(line)\n\t\tif len(line) <= 3 {\n\t\t\tcontinue\n\t\t}\n\t\tanchor := line[:3]\n\t\tline = line[3:]\n\t\tswitch anchor {\n\t\tcase \"no:\":\n\t\t\tsl.Hash = line\n\t\tcase \"ns:\":\n\t\t\tsl.ShortHash = line\n\t\tcase \"nd:\":\n\t\t\tsl.When = line\n\t\tcase \"un:\":\n\t\t\tsl.Author = line\n\t\tcase \"bm:\":\n\t\t\tsl.Bookmark = line\n\t\tcase \"dn:\":\n\t\t\tsl.Description = line\n\t\t}\n\t}\n}\n\nfunc (sl *Sapling) getSaplingCommandOutput(command string, args ...string) string {\n\targs = append([]string{command}, args...)\n\tval, err := sl.env.RunCommand(sl.command, args...)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSpace(val)\n}\n"
  },
  {
    "path": "src/segments/sapling_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nfunc TestSetDir(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tPath     string\n\t\tGOOS     string\n\t}{\n\t\t{\n\t\t\tCase:     \"Linux\",\n\t\t\tExpected: \"/usr/sapling/repo\",\n\t\t\tPath:     \"/usr/sapling/repo/.sl\",\n\t\t\tGOOS:     runtime.LINUX,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Windows\",\n\t\t\tExpected: \"\\\\usr\\\\sapling\\\\repo\",\n\t\t\tPath:     \"\\\\usr\\\\sapling\\\\repo\\\\.sl\",\n\t\t\tGOOS:     runtime.WINDOWS,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\thome := \"/usr/home\"\n\t\tif tc.GOOS == runtime.WINDOWS {\n\t\t\thome = \"\\\\usr\\\\home\"\n\t\t}\n\t\tenv.On(\"Home\").Return(home)\n\n\t\tsl := &Sapling{}\n\t\tsl.Init(options.Map{}, env)\n\n\t\tsl.setDir(tc.Path)\n\t\tassert.Equal(t, tc.Expected, sl.Dir, tc.Case)\n\t}\n}\n\nfunc TestSetCommitContext(t *testing.T) {\n\tcases := []struct {\n\t\tCase   string\n\t\tOutput string\n\t\tError  error\n\n\t\tExpectedHash      string\n\t\tExpectedShortHash string\n\t\tExpectedWhen      string\n\t\tExpectedAuthor    string\n\t\tExpectedBookmark  string\n\t}{\n\t\t{\n\t\t\tCase:  \"Error\",\n\t\t\tError: errors.New(\"error\"),\n\t\t},\n\t\t{\n\t\t\tCase: \"No output\",\n\t\t},\n\t\t{\n\t\t\tCase: \"All output\",\n\t\t\tOutput: `\n\t\t\tno:734349e9f1abd229ec6e9bbebed35aed56b26a9e\n    \t\tns:734349e9f\n    \t\tnd:23 minutes ago\n    \t\tun:jan\n    \t\tbm:sapling-segment\n\t\t\t`,\n\t\t\tExpectedHash:      \"734349e9f1abd229ec6e9bbebed35aed56b26a9e\",\n\t\t\tExpectedShortHash: \"734349e9f\",\n\t\t\tExpectedWhen:      \"23 minutes ago\",\n\t\t\tExpectedAuthor:    \"jan\",\n\t\t\tExpectedBookmark:  \"sapling-segment\",\n\t\t},\n\t\t{\n\t\t\tCase:   \"Short line\",\n\t\t\tOutput: \"er\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"RunCommand\", \"sl\", []string{\"log\", \"--limit\", \"1\", \"--template\", SLCOMMITTEMPLATE}).Return(tc.Output, tc.Error)\n\n\t\tsl := &Sapling{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: SAPLINGCOMMAND,\n\t\t\t},\n\t\t}\n\t\tsl.Init(options.Map{}, env)\n\n\t\tsl.setCommitContext()\n\n\t\tassert.Equal(t, tc.ExpectedHash, sl.Hash, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedShortHash, sl.ShortHash, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedWhen, sl.When, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedAuthor, sl.Author, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBookmark, sl.Bookmark, tc.Case)\n\t}\n}\n\nfunc TestShouldDisplay(t *testing.T) {\n\tcases := []struct {\n\t\tCase       string\n\t\tHasSapling bool\n\t\tInRepo     bool\n\t\tExpected   bool\n\t}{\n\t\t{\n\t\t\tCase: \"Sapling not installed\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"Sapling installed, not in repo\",\n\t\t\tHasSapling: true,\n\t\t},\n\t\t{\n\t\t\tCase:       \"Sapling installed, in repo\",\n\t\t\tHasSapling: true,\n\t\t\tInRepo:     true,\n\t\t\tExpected:   true,\n\t\t},\n\t}\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/sapling/repo/.sl\",\n\t\tParentFolder: \"/sapling/repo\",\n\t\tIsDir:        true,\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasCommand\", \"sl\").Return(tc.HasSapling)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"GOOS\").Return(runtime.LINUX)\n\t\tenv.On(\"Home\").Return(\"/usr/home/sapling\")\n\t\tif tc.InRepo {\n\t\t\tenv.On(\"HasParentFilePath\", \".sl\", false).Return(fileInfo, nil)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \".sl\", false).Return(&runtime.FileInfo{}, errors.New(\"error\"))\n\t\t}\n\n\t\tsl := &Sapling{}\n\t\tsl.Init(&options.Map{}, env)\n\n\t\tgot := sl.shouldDisplay()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t\tif tc.Expected {\n\t\t\tassert.Equal(t, \"/sapling/repo/.sl\", sl.mainSCMDir, tc.Case)\n\t\t\tassert.Equal(t, \"/sapling/repo/.sl\", sl.scmDir, tc.Case)\n\t\t\tassert.Equal(t, \"/sapling/repo\", sl.repoRootDir, tc.Case)\n\t\t\tassert.Equal(t, \"repo\", sl.RepoName, tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestSetHeadContext(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tOutput      string\n\t\tExpected    string\n\t\tFetchStatus bool\n\t}{\n\t\t{\n\t\t\tCase: \"Do not fetch status\",\n\t\t},\n\t\t{\n\t\t\tCase:        \"Fetch status, no output\",\n\t\t\tFetchStatus: true,\n\t\t},\n\t\t{\n\t\t\tCase:        \"Fetch status, changed files\",\n\t\t\tFetchStatus: true,\n\t\t\tOutput: `\n\t\t\tM file.go\n\t\t\tM file2.go\n\t\t\t`,\n\t\t\tExpected: \"~2\",\n\t\t},\n\t\t{\n\t\t\tCase:        \"Fetch status, all cases\",\n\t\t\tFetchStatus: true,\n\t\t\tOutput: `\n\t\t\tM file.go\n\t\t\tR file2.go\n\t\t\tA file3.go\n\t\t\tC file4.go\n\t\t\t! missing.go\n\t\t\t? untracked.go\n\t\t\t? untracked.go\n\t\t\tI ignored.go\n\t\t\tI ignored.go\n\t\t\t`,\n\t\t\tExpected: \"?2 +1 ~1 -1 !1 =1 Ø2\",\n\t\t},\n\t}\n\toutput := `\n\tno:734349e9f1abd229ec6e9bbebed35aed56b26a9e\n\tns:734349e9f\n\tnd:23 minutes ago\n\tun:jan\n\tbm:sapling-segment\n\t`\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"RunCommand\", \"sl\", []string{\"log\", \"--limit\", \"1\", \"--template\", SLCOMMITTEMPLATE}).Return(output, nil)\n\t\tenv.On(\"RunCommand\", \"sl\", []string{\"status\"}).Return(tc.Output, nil)\n\n\t\tprops := &options.Map{\n\t\t\tFetchStatus: tc.FetchStatus,\n\t\t}\n\n\t\tsl := &Sapling{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: SAPLINGCOMMAND,\n\t\t\t},\n\t\t}\n\t\tsl.Init(props, env)\n\n\t\tsl.setHeadContext()\n\t\tgot := sl.Working.String()\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/scm.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nconst (\n\t// Fallback to native command\n\tNativeFallback options.Option = \"native_fallback\"\n\t// Override the built-in status formats\n\tStatusFormats options.Option = \"status_formats\"\n)\n\n// ScmStatus represents part of the status of a repository\ntype ScmStatus struct {\n\tFormats    map[string]string\n\tUnmerged   int\n\tDeleted    int\n\tAdded      int\n\tModified   int\n\tMoved      int\n\tConflicted int\n\tUntracked  int\n\tClean      int\n\tMissing    int\n\tIgnored    int\n}\n\nfunc (s *ScmStatus) Changed() bool {\n\treturn s.Unmerged > 0 ||\n\t\ts.Added > 0 ||\n\t\ts.Deleted > 0 ||\n\t\ts.Modified > 0 ||\n\t\ts.Moved > 0 ||\n\t\ts.Conflicted > 0 ||\n\t\ts.Untracked > 0 ||\n\t\ts.Clean > 0 ||\n\t\ts.Missing > 0 ||\n\t\ts.Ignored > 0\n}\n\nfunc (s *ScmStatus) String() string {\n\tstatus := text.NewBuilder()\n\n\tif s.Formats == nil {\n\t\ts.Formats = make(map[string]string)\n\t}\n\n\tstringIfValue := func(value int, name, prefix string) {\n\t\tif value <= 0 {\n\t\t\treturn\n\t\t}\n\n\t\t// allow user override for prefix\n\t\tif _, ok := s.Formats[name]; ok {\n\t\t\tstatus.WriteString(fmt.Sprintf(s.Formats[name], value))\n\t\t\treturn\n\t\t}\n\n\t\tstatus.WriteString(fmt.Sprintf(\" %s%d\", prefix, value))\n\t}\n\n\tstringIfValue(s.Untracked, \"Untracked\", \"?\")\n\tstringIfValue(s.Added, \"Added\", \"+\")\n\tstringIfValue(s.Modified, \"Modified\", \"~\")\n\tstringIfValue(s.Deleted, \"Deleted\", \"-\")\n\tstringIfValue(s.Moved, \"Moved\", \">\")\n\tstringIfValue(s.Unmerged, \"Unmerged\", \"x\")\n\tstringIfValue(s.Conflicted, \"Conflicted\", \"!\")\n\tstringIfValue(s.Missing, \"Missing\", \"!\")\n\tstringIfValue(s.Clean, \"Clean\", \"=\")\n\tstringIfValue(s.Ignored, \"Ignored\", \"Ø\")\n\n\treturn strings.TrimSpace(status.String())\n}\n\ntype Scm struct {\n\tBase\n\n\tDir             string\n\tRepoName        string\n\tUpstream        string\n\tmainSCMDir      string\n\tscmDir          string\n\trepoRootDir     string\n\tcommand         string\n\tIsWslSharedPath bool\n\tCommandMissing  bool\n\tnativeFallback  bool\n}\n\nconst (\n\t// BranchTemplate allows to specify a template for the branch name\n\tBranchTemplate options.Option = \"branch_template\"\n)\n\nfunc (s *Scm) RelativeDir() string {\n\tif s.repoRootDir == \"\" {\n\t\treturn \"\"\n\t}\n\n\tpwd := s.env.Pwd()\n\tlog.Debug(\"repo root dir:\", s.repoRootDir, \"pwd:\", pwd)\n\n\trel, err := filepath.Rel(s.repoRootDir, pwd)\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\tif rel == \".\" || rel == \"\" {\n\t\tlog.Debug(\"repo root dir is the same as the current working directory, returning empty string\")\n\t\treturn \"\"\n\t}\n\n\treturn rel\n}\n\nfunc (s *Scm) formatBranch(branch string) string {\n\tmappedBranches := s.options.KeyValueMap(MappedBranches, make(map[string]string))\n\n\t// sort the keys alphabetically\n\tkeys := make([]string, 0, len(mappedBranches))\n\tfor k := range mappedBranches {\n\t\tkeys = append(keys, k)\n\t}\n\tsort.Strings(keys)\n\n\tconst wildcard = \"*\"\n\n\tfor _, key := range keys {\n\t\tif key == wildcard {\n\t\t\tbranch = mappedBranches[key]\n\t\t\tbreak\n\t\t}\n\n\t\tmatchSubFolders := strings.HasSuffix(key, wildcard)\n\t\tsubfolderKey := strings.TrimSuffix(key, wildcard)\n\n\t\tif matchSubFolders && strings.HasPrefix(branch, subfolderKey) {\n\t\t\tbranch = strings.Replace(branch, subfolderKey, mappedBranches[key], 1)\n\t\t\tbreak\n\t\t}\n\n\t\tif matchSubFolders || branch != key {\n\t\t\tcontinue\n\t\t}\n\n\t\tbranch = strings.Replace(branch, key, mappedBranches[key], 1)\n\t\tbreak\n\t}\n\n\tbranchTemplate := s.options.String(BranchTemplate, \"\")\n\tif branchTemplate == \"\" {\n\t\treturn branch\n\t}\n\n\ttxt, err := template.Render(branchTemplate, struct{ Branch, Upstream string }{Branch: branch, Upstream: s.Upstream})\n\tif err != nil {\n\t\treturn branch\n\t}\n\n\treturn txt\n}\n\nfunc (s *Scm) fileContent(folder, file string) string {\n\treturn strings.Trim(s.env.FileContent(folder+\"/\"+file), \" \\r\\n\")\n}\n\nfunc (s *Scm) convertToWindowsPath(path string) string {\n\t// only convert when in Windows, or when in a WSL shared folder and not using the native fallback\n\tif s.env.GOOS() == runtime.WINDOWS || (s.IsWslSharedPath && !s.nativeFallback) {\n\t\treturn s.env.ConvertToWindowsPath(path)\n\t}\n\n\treturn path\n}\n\nfunc (s *Scm) convertToLinuxPath(path string) string {\n\tif !s.IsWslSharedPath {\n\t\treturn path\n\t}\n\n\treturn s.env.ConvertToLinuxPath(path)\n}\n\nfunc (s *Scm) hasCommand(command string) bool {\n\tif len(s.command) > 0 {\n\t\treturn true\n\t}\n\n\t// when in a WSL shared folder, we must use command.exe and convert paths accordingly\n\t// for worktrees, stashes, and path to work, except when native_fallback is set\n\ts.IsWslSharedPath = s.env.InWSLSharedDrive()\n\tif s.env.GOOS() == runtime.WINDOWS || s.IsWslSharedPath {\n\t\tcommand += \".exe\"\n\t}\n\n\tif s.env.HasCommand(command) {\n\t\ts.command = command\n\t\treturn true\n\t}\n\n\ts.CommandMissing = true\n\n\t// only use the native fallback when set by the user\n\tif s.IsWslSharedPath && s.options.Bool(NativeFallback, false) {\n\t\tcommand = strings.TrimSuffix(command, \".exe\")\n\t\tif s.env.HasCommand(command) {\n\t\t\ts.command = command\n\t\t\ts.nativeFallback = true\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/scm_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestScmStatusChanged(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tStatus   ScmStatus\n\t\tExpected bool\n\t}{\n\t\t{\n\t\t\tCase:     \"No changes\",\n\t\t\tExpected: false,\n\t\t\tStatus:   ScmStatus{},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Added\",\n\t\t\tExpected: true,\n\t\t\tStatus: ScmStatus{\n\t\t\t\tAdded: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Moved\",\n\t\t\tExpected: true,\n\t\t\tStatus: ScmStatus{\n\t\t\t\tMoved: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Modified\",\n\t\t\tExpected: true,\n\t\t\tStatus: ScmStatus{\n\t\t\t\tModified: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Deleted\",\n\t\t\tExpected: true,\n\t\t\tStatus: ScmStatus{\n\t\t\t\tDeleted: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Unmerged\",\n\t\t\tExpected: true,\n\t\t\tStatus: ScmStatus{\n\t\t\t\tUnmerged: 1,\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, tc.Status.Changed(), tc.Case)\n\t}\n}\n\nfunc TestScmStatusString(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tStatus   ScmStatus\n\t}{\n\t\t{\n\t\t\tCase:     \"Unmerged\",\n\t\t\tExpected: \"x1\",\n\t\t\tStatus: ScmStatus{\n\t\t\t\tUnmerged: 1,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Unmerged and Modified\",\n\t\t\tExpected: \"~3 x1\",\n\t\t\tStatus: ScmStatus{\n\t\t\t\tUnmerged: 1,\n\t\t\t\tModified: 3,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:   \"Empty\",\n\t\t\tStatus: ScmStatus{},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Format override\",\n\t\t\tExpected: \"Added: 1\",\n\t\t\tStatus: ScmStatus{\n\t\t\t\tAdded: 1,\n\t\t\t\tFormats: map[string]string{\n\t\t\t\t\t\"Added\": \"Added: %d\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tassert.Equal(t, tc.Expected, tc.Status.String(), tc.Case)\n\t}\n}\n\nfunc TestHasCommand(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedCommand string\n\t\tCommand         string\n\t\tGOOS            string\n\t\tIsWslSharedPath bool\n\t\tNativeFallback  bool\n\t}{\n\t\t{Case: \"On Windows\", ExpectedCommand: \"git.exe\", GOOS: runtime.WINDOWS},\n\t\t{Case: \"Cache\", ExpectedCommand: \"git.exe\", Command: \"git.exe\"},\n\t\t{Case: \"Non Windows\", ExpectedCommand: \"git\"},\n\t\t{Case: \"Iside WSL2, non shared\", ExpectedCommand: \"git\"},\n\t\t{Case: \"Iside WSL2, shared\", ExpectedCommand: \"git.exe\", IsWslSharedPath: true},\n\t\t{Case: \"Iside WSL2, shared fallback\", ExpectedCommand: \"git\", IsWslSharedPath: true, NativeFallback: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\tenv.On(\"InWSLSharedDrive\").Return(tc.IsWslSharedPath)\n\t\tenv.On(\"HasCommand\", \"git\").Return(true)\n\t\tenv.On(\"HasCommand\", \"git.exe\").Return(!tc.NativeFallback)\n\n\t\tprops := options.Map{\n\t\t\tNativeFallback: tc.NativeFallback,\n\t\t}\n\n\t\ts := &Scm{\n\t\t\tcommand: tc.Command,\n\t\t}\n\t\ts.Init(props, env)\n\n\t\t_ = s.hasCommand(GITCOMMAND)\n\t\tassert.Equal(t, tc.ExpectedCommand, s.command, tc.Case)\n\t}\n}\n\nfunc TestFormatBranch(t *testing.T) {\n\tcases := []struct {\n\t\tMappedBranches map[string]string\n\t\tCase           string\n\t\tExpected       string\n\t\tInput          string\n\t\tBranchTemplate string\n\t\tUpstream       string\n\t}{\n\t\t{\n\t\t\tCase:     \"No settings\",\n\t\t\tInput:    \"main\",\n\t\t\tExpected: \"main\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"BranchMaxLength higher than branch name\",\n\t\t\tInput:          \"main\",\n\t\t\tExpected:       \"main\",\n\t\t\tBranchTemplate: \"{{ trunc 5 .Branch }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"BranchMaxLength lower than branch name\",\n\t\t\tInput:          \"feature/test-this-branch\",\n\t\t\tExpected:       \"featu\",\n\t\t\tBranchTemplate: \"{{ trunc 5 .Branch }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"BranchMaxLength lower than branch name, with truncate symbol\",\n\t\t\tInput:          \"feature/test-this-branch\",\n\t\t\tExpected:       \"feat…\",\n\t\t\tBranchTemplate: \"{{ truncE 5 .Branch }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"BranchMaxLength lower than branch name, with truncate symbol and no FullBranchPath\",\n\t\t\tInput:          \"feature/test-this-branch\",\n\t\t\tExpected:       \"test…\",\n\t\t\tBranchTemplate: \"{{ truncE 5 (base .Branch) }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"BranchMaxLength lower to branch name, with truncate symbol\",\n\t\t\tInput:          \"feat\",\n\t\t\tExpected:       \"feat\",\n\t\t\tBranchTemplate: \"{{ trunc 5 .Branch }}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Branch mapping, no BranchMaxLength\",\n\t\t\tInput:    \"feat/my-new-feature\",\n\t\t\tExpected: \"🚀 my-new-feature\",\n\t\t\tMappedBranches: map[string]string{\n\t\t\t\t\"feat/*\": \"🚀 \",\n\t\t\t\t\"bug/*\":  \"🐛 \",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Branch mapping, with BranchMaxLength\",\n\t\t\tInput:          \"feat/my-new-feature\",\n\t\t\tExpected:       \"🚀 my-\",\n\t\t\tBranchTemplate: \"{{ trunc 5 .Branch }}\",\n\t\t\tMappedBranches: map[string]string{\n\t\t\t\t\"feat/*\": \"🚀 \",\n\t\t\t\t\"bug/*\":  \"🐛 \",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"Branch with upstream\",\n\t\t\tInput:          \"feat/my-new-feature\",\n\t\t\tExpected:       \"feat/my-new-feature@origin\",\n\t\t\tUpstream:       \"origin\",\n\t\t\tBranchTemplate: \"{{ .Branch }}{{ if .Upstream }}@{{ .Upstream }}{{ end }}\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tMappedBranches: tc.MappedBranches,\n\t\t\tBranchTemplate: tc.BranchTemplate,\n\t\t}\n\n\t\ts := &Scm{\n\t\t\tUpstream: tc.Upstream,\n\t\t}\n\t\ts.Init(props, nil)\n\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(shell.BASH)\n\t\ttemplate.Cache = new(cache.Template)\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tgot := s.formatBranch(tc.Input)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/session.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\ntype Session struct {\n\tBase\n\n\tSSHSession bool\n}\n\nfunc (s *Session) Enabled() bool {\n\ts.SSHSession = s.activeSSHSession()\n\treturn true\n}\n\nfunc (s *Session) Template() string {\n\treturn \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }} \"\n}\n\nfunc (s *Session) activeSSHSession() bool {\n\tkeys := []string{\n\t\t\"SSH_CONNECTION\",\n\t\t\"SSH_CLIENT\",\n\t}\n\n\tfor _, key := range keys {\n\t\tcontent := s.env.Getenv(key)\n\t\tif content != \"\" {\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif s.env.Platform() == runtime.WINDOWS {\n\t\treturn false\n\t}\n\n\twhoAmI, err := s.env.RunCommand(\"who\", \"am\", \"i\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treturn regex.MatchString(`\\(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\)`, whoAmI)\n}\n"
  },
  {
    "path": "src/segments/session_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSessionSegmentTemplate(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tUserName       string\n\t\tComputerName   string\n\t\tTemplate       string\n\t\tWhoAmI         string\n\t\tPlatform       string\n\t\tSSHSession     bool\n\t\tRoot           bool\n\t}{\n\t\t{\n\t\t\tCase:           \"user and computer\",\n\t\t\tExpectedString: \"john@company-laptop\",\n\t\t\tComputerName:   \"company-laptop\",\n\t\t\tUserName:       \"john\",\n\t\t\tTemplate:       \"{{.UserName}}@{{.HostName}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"user only\",\n\t\t\tExpectedString: \"john\",\n\t\t\tUserName:       \"john\",\n\t\t\tTemplate:       \"{{.UserName}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"user with ssh\",\n\t\t\tExpectedString: \"john on remote\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     true,\n\t\t\tComputerName:   \"remote\",\n\t\t\tTemplate:       \"{{.UserName}}{{if .SSHSession}} on {{.HostName}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"user without ssh\",\n\t\t\tExpectedString: \"john\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     false,\n\t\t\tComputerName:   \"remote\",\n\t\t\tTemplate:       \"{{.UserName}}{{if .SSHSession}} on {{.HostName}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"user with root and ssh\",\n\t\t\tExpectedString: \"super john on remote\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     true,\n\t\t\tComputerName:   \"remote\",\n\t\t\tRoot:           true,\n\t\t\tTemplate:       \"{{if .Root}}super {{end}}{{.UserName}}{{if .SSHSession}} on {{.HostName}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"no template\",\n\t\t\tExpectedString: \"\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     true,\n\t\t\tComputerName:   \"remote\",\n\t\t\tRoot:           true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"user with ssh using who am i\",\n\t\t\tExpectedString: \"john on remote\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     false,\n\t\t\tWhoAmI:         \"sascha   pts/1        2023-11-08 22:56 (89.246.1.1)\",\n\t\t\tComputerName:   \"remote\",\n\t\t\tTemplate:       \"{{.UserName}}{{if .SSHSession}} on {{.HostName}}{{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"user with ssh using who am i (windows)\",\n\t\t\tExpectedString: \"john\",\n\t\t\tUserName:       \"john\",\n\t\t\tSSHSession:     false,\n\t\t\tWhoAmI:         \"sascha   pts/1        2023-11-08 22:56 (89.246.1.1)\",\n\t\t\tPlatform:       runtime.WINDOWS,\n\t\t\tComputerName:   \"remote\",\n\t\t\tTemplate:       \"{{.UserName}}{{if .SSHSession}} on {{.HostName}}{{end}}\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"User\").Return(tc.UserName)\n\t\tenv.On(\"GOOS\").Return(\"burp\")\n\t\tenv.On(\"Host\").Return(tc.ComputerName, nil)\n\n\t\tvar SSHSession string\n\t\tif tc.SSHSession {\n\t\t\tSSHSession = \"zezzion\"\n\t\t}\n\n\t\tenv.On(\"Getenv\", \"SSH_CONNECTION\").Return(SSHSession)\n\t\tenv.On(\"Getenv\", \"SSH_CLIENT\").Return(SSHSession)\n\n\t\tenv.On(\"Platform\").Return(tc.Platform)\n\n\t\tvar whoAmIErr error\n\t\tif tc.WhoAmI == \"\" {\n\t\t\twhoAmIErr = fmt.Errorf(\"who am i error\")\n\t\t}\n\n\t\tenv.On(\"RunCommand\", \"who\", []string{\"am\", \"i\"}).Return(tc.WhoAmI, whoAmIErr)\n\n\t\tsession := &Session{}\n\t\tsession.Init(options.Map{}, env)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tUserName: tc.UserName,\n\t\t\t\tHostName: tc.ComputerName,\n\t\t\t\tRoot:     tc.Root,\n\t\t\t},\n\t\t}\n\n\t\t_ = session.Enabled()\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, session), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/shell.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Shell struct {\n\tBase\n\n\tName    string\n\tVersion string\n}\n\nconst (\n\t// MappedShellNames allows for custom text in place of shell names\n\tMappedShellNames options.Option = \"mapped_shell_names\"\n)\n\nfunc (s *Shell) Template() string {\n\treturn NameTemplate\n}\n\nfunc (s *Shell) Enabled() bool {\n\tmappedNames := s.options.KeyValueMap(MappedShellNames, make(map[string]string))\n\ts.Name = s.env.Shell()\n\ts.Version = s.env.Flags().ShellVersion\n\tfor key, val := range mappedNames {\n\t\tif strings.EqualFold(s.Name, key) {\n\t\t\ts.Name = val\n\t\t\tbreak\n\t\t}\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/shell_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWriteCurrentShell(t *testing.T) {\n\texpected := \"zsh\"\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(expected, nil)\n\tenv.On(\"Flags\").Return(&runtime.Flags{ShellVersion: \"1.2.3\"})\n\n\ts := &Shell{}\n\ts.Init(options.Map{}, env)\n\n\t_ = s.Enabled()\n\tassert.Equal(t, expected, renderTemplate(env, s.Template(), s))\n}\n\nfunc TestUseMappedShellNames(t *testing.T) {\n\tcases := []struct {\n\t\tShell    string\n\t\tExpected string\n\t}{\n\t\t{Shell: \"zsh\", Expected: \"zsh\"},\n\t\t{Shell: \"pwsh\", Expected: \"PS\"},\n\t\t{Shell: \"PWSH\", Expected: \"PS\"},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(tc.Expected, nil)\n\t\tenv.On(\"Flags\").Return(&runtime.Flags{ShellVersion: \"1.2.3\"})\n\n\t\tprops := options.Map{\n\t\t\tMappedShellNames: map[string]string{\"pwsh\": \"PS\"},\n\t\t}\n\n\t\ts := &Shell{}\n\t\ts.Init(props, env)\n\n\t\t_ = s.Enabled()\n\t\tgot := renderTemplate(env, s.Template(), s)\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n"
  },
  {
    "path": "src/segments/sitecore.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"path\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tsitecoreFileName    = \"sitecore.json\"\n\tsitecoreFolderName  = \".sitecore\"\n\tuserFileName        = \"user.json\"\n\tdefaultEndpointName = \"default\"\n)\n\ntype Sitecore struct {\n\tBase\n\n\tEndpointName string\n\tCmHost       string\n}\n\ntype EndpointConfig struct {\n\tHost string `json:\"host\"`\n}\n\ntype UserConfig struct {\n\tEndpoints       map[string]EndpointConfig `json:\"endpoints\"`\n\tDefaultEndpoint string                    `json:\"defaultEndpoint\"`\n}\n\nfunc (s *Sitecore) Enabled() bool {\n\tif !s.env.HasFiles(sitecoreFileName) || !s.env.HasFilesInDir(sitecoreFolderName, userFileName) {\n\t\tlog.Debug(\"sitecore cli configuration files were not found\")\n\t\treturn false\n\t}\n\n\tvar userConfig, err = getUserConfig(s)\n\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\ts.EndpointName = userConfig.getDefaultEndpoint()\n\n\tdisplayDefault := s.options.Bool(options.DisplayDefault, true)\n\n\tif !displayDefault && s.EndpointName == defaultEndpointName {\n\t\tlog.Debug(\"displaying of the default environment is turned off\")\n\t\treturn false\n\t}\n\n\tif endpoint := userConfig.getEndpoint(s.EndpointName); endpoint != nil && len(endpoint.Host) > 0 {\n\t\ts.CmHost = endpoint.Host\n\t}\n\n\treturn true\n}\n\nfunc (s *Sitecore) Template() string {\n\treturn \"{{ .EndpointName }} {{ if .CmHost }}({{ .CmHost }}){{ end }}\"\n}\n\nfunc getUserConfig(s *Sitecore) (*UserConfig, error) {\n\tuserJSON := s.env.FileContent(path.Join(sitecoreFolderName, userFileName))\n\tvar userConfig UserConfig\n\n\tif err := json.Unmarshal([]byte(userJSON), &userConfig); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &userConfig, nil\n}\n\nfunc (u *UserConfig) getDefaultEndpoint() string {\n\tif len(u.DefaultEndpoint) > 0 {\n\t\treturn u.DefaultEndpoint\n\t}\n\n\treturn defaultEndpointName\n}\n\nfunc (u *UserConfig) getEndpoint(name string) *EndpointConfig {\n\tendpoint, exists := u.Endpoints[name]\n\n\tif exists {\n\t\treturn &endpoint\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/sitecore_test.go",
    "content": "package segments\n\nimport (\n\t\"path\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSitecoreSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tExpectedString     string\n\t\tUserFileContent    string\n\t\tExpectedEnabled    bool\n\t\tSitecoreFileExists bool\n\t\tUserFileExists     bool\n\t\tDisplayDefault     bool\n\t}{\n\t\t{Case: \"Disabled, no sitecore.json file and user.json file\", ExpectedString: \"\", ExpectedEnabled: false, SitecoreFileExists: false, UserFileExists: false},\n\t\t{Case: \"Disabled, only sitecore.json file exists\", ExpectedString: \"\", ExpectedEnabled: false, SitecoreFileExists: true, UserFileExists: false},\n\t\t{Case: \"Disabled, only user.json file exists\", ExpectedString: \"\", ExpectedEnabled: false, SitecoreFileExists: false, UserFileExists: true},\n\t\t{\n\t\t\tCase:               \"Disabled, user.json is empty\",\n\t\t\tExpectedString:     \"\",\n\t\t\tExpectedEnabled:    false,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    \"\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Disabled, user.json contains non-json text\",\n\t\t\tExpectedString:     \"\",\n\t\t\tExpectedEnabled:    false,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONNotJSONFormat,\n\t\t},\n\t\t{\n\t\t\tCase:               \"Disabled with default endpoint\",\n\t\t\tExpectedString:     \"default\",\n\t\t\tExpectedEnabled:    false,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONOnlyDefaultEnv,\n\t\t\tDisplayDefault:     false,\n\t\t},\n\t\t{\n\t\t\tCase:               \"Enabled, user.json initial state\",\n\t\t\tExpectedString:     \"default\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONDefaultEmpty,\n\t\t\tDisplayDefault:     true,\n\t\t},\n\t\t{\n\t\t\tCase:               \"Enabled, user.json with custom default endpoint and without endpoints\",\n\t\t\tExpectedString:     \"MySuperEnv\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONCustomDefaultEnvWithoutEndpoints,\n\t\t},\n\t\t{\n\t\t\tCase:               \"Enabled, user.json with custom default endpoint and configured endpoints\",\n\t\t\tExpectedString:     \"myEnv (https://host.com)\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONCustomDefaultEnv,\n\t\t},\n\t\t{\n\t\t\tCase:               \"Enabled, user.json with custom default endpoint and empty host\",\n\t\t\tExpectedString:     \"envWithEmptyHost\",\n\t\t\tExpectedEnabled:    true,\n\t\t\tSitecoreFileExists: true,\n\t\t\tUserFileExists:     true,\n\t\t\tUserFileContent:    testUserJSONCustomDefaultEnvAndEmptyHost,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HasFiles\", \"sitecore.json\").Return(tc.SitecoreFileExists)\n\t\tenv.On(\"HasFilesInDir\", \".sitecore\", \"user.json\").Return(tc.UserFileExists)\n\t\tenv.On(\"FileContent\", path.Join(\".sitecore\", \"user.json\")).Return(tc.UserFileContent)\n\n\t\tprops := options.Map{\n\t\t\toptions.DisplayDefault: tc.DisplayDefault,\n\t\t}\n\n\t\tsitecore := &Sitecore{}\n\t\tsitecore.Init(props, env)\n\t\tassert.Equal(t, tc.ExpectedEnabled, sitecore.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, sitecore.Template(), sitecore), tc.Case)\n\t}\n}\n\nvar testUserJSONDefaultEmpty = `\n{\n\t\"endpoints\": {}\n}`\n\nvar testUserJSONCustomDefaultEnvWithoutEndpoints = `\n{\n\t\"endpoints\": {},\n\t\"defaultEndpoint\": \"MySuperEnv\"\n}`\n\nvar testUserJSONCustomDefaultEnv = `\n{\n\t\"endpoints\": {\n\t\t\"myEnv\": {\n\t\t\t\"host\": \"https://host.com\"\n\t\t}\n\t},\n\t\"defaultEndpoint\": \"myEnv\"\n}`\n\nvar testUserJSONCustomDefaultEnvAndEmptyHost = `\n{\n\t\"endpoints\": {\n\t\t\"myEnv\": {\n\t\t\t\"host\": \"\"\n\t\t}\n\t},\n\t\"defaultEndpoint\": \"envWithEmptyHost\"\n}`\n\nvar testUserJSONNotJSONFormat = `\n---\n doe: \"a deer, a female deer\"\n ray: \"a drop of golden sun\"\n pi: 3.14159\n xmas: true\n french-hens: 3\n calling-birds:\n   - huey\n   - dewey\n   - louie\n   - fred\n xmas-fifth-day:\n   calling-birds: four\n   french-hens: 3\n   golden-rings: 5\n   partridges:\n     count: 1\n     location: \"a pear tree\"\n   turtle-doves: two`\n\nvar testUserJSONOnlyDefaultEnv = `\n{\n\t\"endpoints\": {\n\t\t\"default\": {\n\t\t\t\"host\": \"https://host.com\"\n\t\t}\n\t}\n}`\n"
  },
  {
    "path": "src/segments/spotify.go",
    "content": "package segments\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\ntype Spotify struct {\n\tBase\n\n\tMusicPlayer\n}\n\ntype MusicPlayer struct {\n\tStatus string\n\tArtist string\n\tTrack  string\n\tIcon   string\n}\n\nconst (\n\t// PlayingIcon indicates a song is playing\n\tPlayingIcon options.Option = \"playing_icon\"\n\t// PausedIcon indicates a song is paused\n\tPausedIcon options.Option = \"paused_icon\"\n\t// StoppedIcon indicates a song is stopped\n\tStoppedIcon options.Option = \"stopped_icon\"\n\t// AdIcon indicates an advertisement is playing\n\tAdIcon options.Option = \"ad_icon\"\n\n\tplaying = \"playing\"\n\tstopped = \"stopped\"\n\tpaused  = \"paused\"\n)\n\nfunc (s *Spotify) Template() string {\n\treturn \" {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \"\n}\n\nfunc (s *Spotify) resolveIcon() {\n\tswitch s.Status {\n\tcase stopped:\n\t\t// in this case, no artist or track info\n\t\ts.Icon = s.options.String(StoppedIcon, \"\\uf04d \")\n\tcase paused:\n\t\ts.Icon = s.options.String(PausedIcon, \"\\uf04c \")\n\tcase playing:\n\t\ts.Icon = s.options.String(PlayingIcon, \"\\ue602 \")\n\t}\n}\n"
  },
  {
    "path": "src/segments/spotify_darwin.go",
    "content": "//go:build darwin\n\npackage segments\n\nimport \"strings\"\n\nfunc (s *Spotify) Enabled() bool {\n\t// Batching commands to reduce latency. Each individual call to `osascript` creates additional delays.\n\t// Using '|' as a delimiter in the batched command since it's unlikely\n\t// to appear in track or artist names, making it safe for splitting the output\n\tbatchedCommand := `\n\tif application \"Spotify\" is running then\n\t\ttell application \"Spotify\"\n\t\t\tset playerState to player state as string\n\t\t\tset artistName to \"\"\n\t\t\tset trackName to \"\"\n\t\t\tif playerState is not \"stopped\" then\n\t\t\t\tset artistName to artist of current track as string\n\t\t\t\tset trackName to name of current track as string\n\t\t\tend if\n\t\t\treturn \"true|\" & playerState & \"|\" & artistName & \"|\" & trackName\n\t\tend tell\n\telse\n\t\treturn \"false|||\"\n\tend if\n\t`\n\n\tbatchedOutput := s.runAppleScriptCommand(batchedCommand)\n\n\toutputStrings := strings.SplitN(batchedOutput, \"|\", 4)\n\tif outputStrings[0] == \"false\" || outputStrings[0] == \"\" || len(outputStrings) != 4 {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\ts.Status = outputStrings[1]\n\n\t// Check if running\n\tif s.Status == \"\" {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\tif s.Status == stopped {\n\t\treturn false\n\t}\n\n\ts.Artist = outputStrings[2]\n\ts.Track = outputStrings[3]\n\ts.resolveIcon()\n\n\treturn true\n}\n\nfunc (s *Spotify) runAppleScriptCommand(command string) string {\n\tval, _ := s.env.RunCommand(\"osascript\", \"-e\", command)\n\treturn val\n}\n"
  },
  {
    "path": "src/segments/spotify_darwin_test.go",
    "content": "//go:build darwin\n\npackage segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSpotifyDarwinEnabledAndSpotifyPlaying(t *testing.T) {\n\tcases := []struct {\n\t\tError       error\n\t\tBatchedCase string\n\t\tExpected    string\n\t\tEnabled     bool\n\t}{\n\t\t{BatchedCase: \"false|||\", Expected: \"\", Enabled: false},\n\t\t{BatchedCase: \"false||\", Expected: \"\", Error: errors.New(\"oops\"), Enabled: false},\n\t\t{BatchedCase: \"true|playing|Candlemass|Spellbreaker\", Expected: \"\\ue602 Candlemass - Spellbreaker\", Enabled: true},\n\t\t{BatchedCase: \"true|paused|Candlemass|Spellbreaker\", Expected: \"\\uf04c Candlemass - Spellbreaker\", Enabled: true},\n\t}\n\tbatchedCommand := `\n\tif application \"Spotify\" is running then\n\t\ttell application \"Spotify\"\n\t\t\tset playerState to player state as string\n\t\t\tset artistName to \"\"\n\t\t\tset trackName to \"\"\n\t\t\tif playerState is not \"stopped\" then\n\t\t\t\tset artistName to artist of current track as string\n\t\t\t\tset trackName to name of current track as string\n\t\t\tend if\n\t\t\treturn \"true|\" & playerState & \"|\" & artistName & \"|\" & trackName\n\t\tend tell\n\telse\n\t\treturn \"false|||\"\n\tend if\n\t`\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"RunCommand\", \"osascript\", []string{\"-e\", batchedCommand}).Return(tc.BatchedCase, tc.Error)\n\n\t\ts := &Spotify{}\n\t\ts.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.Enabled, s.Enabled())\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, s.Template(), s))\n\t}\n}\n"
  },
  {
    "path": "src/segments/spotify_linux.go",
    "content": "//go:build linux && !darwin && !windows\n\npackage segments\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n)\n\nfunc (s *Spotify) Enabled() bool {\n\t// Check if we're in WSL and handle that separately\n\tif s.env.IsWsl() {\n\t\treturn s.enabledWsl()\n\t}\n\n\t// Standard Linux implementation\n\trunning := s.runLinuxScriptCommand(\" string:PlaybackStatus | awk -F '\\\"' '/string/ {print tolower($2)}'\")\n\n\tif strings.HasPrefix(running, \"Error\") || running == \"\" {\n\t\treturn false\n\t}\n\n\tif strings.Contains(running, \"Error.ServiceUnknown\") || strings.HasSuffix(running, \"-\") {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\tif running == stopped {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\ts.Status = running\n\ts.Artist = s.runLinuxScriptCommand(\" string:Metadata | awk -F '\\\"' 'BEGIN {RS=\\\"entry\\\"}; /'xesam:artist'/ {a=$4} END {print a}'\")\n\ts.Track = s.runLinuxScriptCommand(\" string:Metadata | awk -F '\\\"' 'BEGIN {RS=\\\"entry\\\"}; /'xesam:title'/ {t=$4} END {print t}'\")\n\ts.resolveIcon()\n\n\treturn true\n}\n\nfunc (s *Spotify) runLinuxScriptCommand(command string) string {\n\tdbusCMD := \"dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player\"\n\tval := s.env.RunShellCommand(shell.BASH, dbusCMD+command)\n\treturn val\n}\n\nfunc (s *Spotify) enabledWsl() bool {\n\tpsCommand := `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; (Get-Process Spotify -ErrorAction SilentlyContinue | Where-Object {$_.MainWindowTitle -ne \"\"} | Select-Object -First 1).MainWindowTitle` //nolint: lll\n\n\twindowName, err := s.env.RunCommand(\"powershell.exe\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", psCommand)\n\tif err != nil {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\ttitle := strings.TrimSpace(windowName)\n\tif title == \"\" || !strings.Contains(title, \" - \") {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\tartist, track, found := strings.Cut(title, \" - \")\n\tif !found {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\ts.Artist = strings.TrimSpace(artist)\n\ts.Track = strings.TrimSpace(track)\n\n\tif s.Artist == \"\" || s.Track == \"\" {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\ts.Status = playing\n\ts.resolveIcon()\n\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/spotify_linux_test.go",
    "content": "//go:build linux && !darwin && !windows\n\npackage segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSpotifyLinux(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tStatus          string\n\t\tArtist          string\n\t\tTrack           string\n\t\tExpected        string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{Case: \"no data\", ExpectedEnabled: false},\n\t\t{Case: \"error\", ExpectedEnabled: false, Status: \"Error.ServiceUnknown\"},\n\t\t{Case: \"paused\", ExpectedEnabled: true, Expected: \"\\uf04c Candlemass - Spellbreaker\", Status: \"paused\", Artist: \"Candlemass\", Track: \"Spellbreaker\"},\n\t\t{Case: \"playing\", ExpectedEnabled: true, Expected: \"\\ue602 Candlemass - Spellbreaker\", Status: \"playing\", Artist: \"Candlemass\", Track: \"Spellbreaker\"},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"IsWsl\").Return(false)\n\n\t\tdbusCMD := \"dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player\"\n\t\tenv.On(\"RunShellCommand\", shell.BASH, dbusCMD+\" string:PlaybackStatus | awk -F '\\\"' '/string/ {print tolower($2)}'\").Return(tc.Status)\n\t\tenv.On(\"RunShellCommand\", shell.BASH, dbusCMD+\" string:Metadata | awk -F '\\\"' 'BEGIN {RS=\\\"entry\\\"}; /'xesam:artist'/ {a=$4} END {print a}'\").Return(tc.Artist)\n\t\tenv.On(\"RunShellCommand\", shell.BASH, dbusCMD+\" string:Metadata | awk -F '\\\"' 'BEGIN {RS=\\\"entry\\\"}; /'xesam:title'/ {t=$4} END {print t}'\").Return(tc.Track)\n\n\t\ts := &Spotify{}\n\t\ts.Init(options.Map{}, env)\n\n\t\tgot := s.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, got, tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.Expected, renderTemplate(env, s.Template(), s), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestSpotifyWSL(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tError           error\n\t\tTitle           string\n\t\tExpected        string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{Case: \"nothing\"},\n\t\t{Case: \"error\", Error: errors.New(\"oops\")},\n\t\t{Case: \"title\", ExpectedEnabled: true, Expected: \"\\ue602 Xzibit - Crash (ft. Royce Da 5'9\\\" K.A.A.N.)\", Title: `Xzibit - Crash (ft. Royce Da 5'9\" K.A.A.N.)`},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"IsWsl\").Return(true)\n\n\t\tpsCommand := `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; (Get-Process Spotify -ErrorAction SilentlyContinue | Where-Object {$_.MainWindowTitle -ne \"\"} | Select-Object -First 1).MainWindowTitle` //nolint: lll\n\t\tenv.On(\"RunCommand\", \"powershell.exe\", []string{\"-NoProfile\", \"-NonInteractive\", \"-Command\", psCommand}).Return(tc.Title, tc.Error)\n\n\t\ts := &Spotify{}\n\t\ts.Init(options.Map{}, env)\n\n\t\tgot := s.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, got, tc.Case)\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.Expected, renderTemplate(env, s.Template(), s), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/spotify_noop.go",
    "content": "//go:build !linux && !darwin && !windows\n\npackage segments\n\nfunc (s *Spotify) Enabled() bool {\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/spotify_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSpotifyStringPlayingSong(t *testing.T) {\n\texpected := \"\\ue602 Candlemass - Spellbreaker\"\n\tenv := new(mock.Environment)\n\n\ts := &Spotify{\n\t\tMusicPlayer: MusicPlayer{\n\t\t\tArtist: \"Candlemass\",\n\t\t\tTrack:  \"Spellbreaker\",\n\t\t\tStatus: \"playing\",\n\t\t\tIcon:   \"\\ue602 \",\n\t\t},\n\t}\n\ts.Init(options.Map{}, env)\n\n\tassert.Equal(t, expected, renderTemplate(env, s.Template(), s))\n}\n\nfunc TestSpotifyStringStoppedSong(t *testing.T) {\n\texpected := \"\\uf04d\"\n\tenv := new(mock.Environment)\n\n\ts := &Spotify{\n\t\tMusicPlayer: MusicPlayer{\n\t\t\tArtist: \"Candlemass\",\n\t\t\tTrack:  \"Spellbreaker\",\n\t\t\tStatus: \"stopped\",\n\t\t\tIcon:   \"\\uf04d \",\n\t\t},\n\t}\n\ts.Init(options.Map{}, env)\n\n\tassert.Equal(t, expected, renderTemplate(env, s.Template(), s))\n}\n"
  },
  {
    "path": "src/segments/spotify_windows.go",
    "content": "//go:build windows\n\npackage segments\n\nimport (\n\t\"strings\"\n)\n\nfunc (s *Spotify) Enabled() bool {\n\t// search for spotify window to retrieve the title\n\t// Can be either \"Spotify xxx\" or the song name \"Candlemass - Spellbreaker\"\n\twindowTitle, err := s.env.QueryWindowTitles(\"spotify.exe\", `^(Spotify.*)|(.*\\s-\\s.*)$`)\n\tif err == nil {\n\t\treturn s.parseNativeTitle(windowTitle)\n\t}\n\twindowTitle, err = s.env.QueryWindowTitles(\"msedge.exe\", `^(Spotify.*)`)\n\tif err != nil {\n\t\treturn false\n\t}\n\treturn s.parseWebTitle(windowTitle)\n}\n\nfunc (s *Spotify) parseNativeTitle(windowTitle string) bool {\n\tseparator := \" - \"\n\n\tif !strings.Contains(windowTitle, separator) {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\tbefore, after, _ := strings.Cut(windowTitle, separator)\n\ts.Artist = before\n\ts.Track = after\n\ts.Status = playing\n\ts.resolveIcon()\n\treturn true\n}\n\nfunc (s *Spotify) parseWebTitle(windowTitle string) bool {\n\twindowTitle = strings.TrimPrefix(windowTitle, \"Spotify - \")\n\tseparator := \" • \"\n\n\tif !strings.Contains(windowTitle, separator) {\n\t\ts.Status = stopped\n\t\treturn false\n\t}\n\n\tbefore, after, _ := strings.Cut(windowTitle, separator)\n\ts.Track = before\n\ts.Artist = after\n\ts.Status = playing\n\ts.resolveIcon()\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/spotify_windows_test.go",
    "content": "//go:build windows\n\npackage segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSpotifyWindowsNative(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTitle           string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Playing\",\n\t\t\tExpectedString:  \"\\ue602 Candlemass - Spellbreaker\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTitle:           \"Candlemass - Spellbreaker\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Stopped\",\n\t\t\tExpectedEnabled: false,\n\t\t\tTitle:           \"Spotify premium\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Playing - new\",\n\t\t\tExpectedString:  \"\\ue602 Demon Hunter - Collapsing (feat. Björn \\\"Speed\\\" Strid)\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTitle:           `Demon Hunter - Collapsing (feat. Björn \"Speed\" Strid)`,\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"QueryWindowTitles\", \"spotify.exe\", `^(Spotify.*)|(.*\\s-\\s.*)$`).Return(tc.Title, tc.Error)\n\t\tenv.On(\"QueryWindowTitles\", \"msedge.exe\", `^(Spotify.*)`).Return(\"\", &runtime.NotImplemented{})\n\n\t\ts := &Spotify{}\n\t\ts.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, s.Enabled())\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, s.Template(), s))\n\t\t}\n\t}\n}\n\nfunc TestSpotifyWindowsPWA(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTitle           string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Playing\",\n\t\t\tExpectedString:  \"\\ue602 Sarah, the Illstrumentalist - Snow in Stockholm\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTitle:           \"Spotify - Snow in Stockholm • Sarah, the Illstrumentalist\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Playing\",\n\t\t\tExpectedString:  \"\\ue602 Main one - Bring the drama\",\n\t\t\tExpectedEnabled: true,\n\t\t\tTitle:           \"Spotify - Bring the drama • Main one\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"Stopped\",\n\t\t\tExpectedEnabled: false,\n\t\t\tTitle:           \"Spotify - Web Player\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"QueryWindowTitles\", \"spotify.exe\", \"^(Spotify.*)|(.*\\\\s-\\\\s.*)$\").Return(\"\", &runtime.NotImplemented{})\n\t\tenv.On(\"QueryWindowTitles\", \"msedge.exe\", \"^(Spotify.*)\").Return(tc.Title, tc.Error)\n\n\t\ts := &Spotify{}\n\t\ts.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, s.Enabled())\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, s.Template(), s))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/status.go",
    "content": "package segments\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nconst (\n\tStatusTemplate  options.Option = \"status_template\"\n\tStatusSeparator options.Option = \"status_separator\"\n)\n\ntype Status struct {\n\tBase\n\n\tString  string\n\tMeaning string\n\tError   bool\n}\n\nfunc (s *Status) Template() string {\n\treturn \" {{ .String }} \"\n}\n\nfunc (s *Status) Enabled() bool {\n\tstatus, pipeStatus := s.env.StatusCodes()\n\n\ts.String = s.formatStatus(status, pipeStatus)\n\t// Deprecated: Use {{ reason .Code }} instead\n\ts.Meaning = template.GetReasonFromStatus(status)\n\n\tif s.options.Bool(options.AlwaysEnabled, false) {\n\t\treturn true\n\t}\n\n\treturn s.Error\n}\n\nfunc (s *Status) formatStatus(status int, pipeStatus string) string {\n\tstatusTemplate := s.options.String(StatusTemplate, \"{{ .Code }}\")\n\n\tif status != 0 {\n\t\ts.Error = true\n\t}\n\n\tif pipeStatus == \"\" {\n\t\tif txt, err := template.Render(statusTemplate, s); err == nil {\n\t\t\treturn txt\n\t\t}\n\n\t\treturn strconv.Itoa(status)\n\t}\n\n\tStatusSeparator := s.options.String(StatusSeparator, \"|\")\n\n\tbuilder := text.NewBuilder()\n\n\t// use an anaonymous struct to avoid\n\t// confusion with the template context\n\t// that already has a .Code global property\n\tvar context struct {\n\t\tCode int\n\t}\n\n\tsplitted := strings.Split(pipeStatus, \" \")\n\tfor i, codeStr := range splitted {\n\t\twrite := func(txt string) {\n\t\t\tif i > 0 {\n\t\t\t\tbuilder.WriteString(StatusSeparator)\n\t\t\t}\n\t\t\tbuilder.WriteString(txt)\n\t\t}\n\n\t\tcode, err := strconv.Atoi(codeStr)\n\t\tif err != nil {\n\t\t\twrite(codeStr)\n\t\t\tcontinue\n\t\t}\n\n\t\tif code != 0 {\n\t\t\ts.Error = true\n\t\t}\n\n\t\tcontext.Code = code\n\n\t\ttxt, err := template.Render(statusTemplate, context)\n\t\tif err != nil {\n\t\t\twrite(codeStr)\n\t\t\tcontinue\n\t\t}\n\n\t\twrite(txt)\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "src/segments/status_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStatusWriterEnabled(t *testing.T) {\n\tcases := []struct {\n\t\tTemplate string\n\t\tStatus   int\n\t\tExpected bool\n\t}{\n\t\t{Status: 102, Expected: true},\n\t\t{Status: 0, Expected: false},\n\t\t{Status: -1, Expected: true},\n\t\t{Status: 144, Expected: true, Template: \"{{}}\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"StatusCodes\").Return(tc.Status, \"\")\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\n\t\tprops := options.Map{}\n\t\tif len(tc.Template) > 0 {\n\t\t\tprops[StatusTemplate] = tc.Template\n\t\t}\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tCode: 133,\n\t\t\t},\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\ts := &Status{}\n\t\ts.Init(props, env)\n\n\t\tassert.Equal(t, tc.Expected, s.Enabled())\n\t}\n}\n\nfunc TestFormatStatus(t *testing.T) {\n\tcases := []struct {\n\t\tCase       string\n\t\tPipeStatus string\n\t\tTemplate   string\n\t\tSeparator  string\n\t\tExpected   string\n\t\tStatus     int\n\t}{\n\t\t// {\n\t\t// \tCase:      \"No PipeStatus\",\n\t\t// \tStatus:    12,\n\t\t// \tTemplate:  \"{{ .Code }}\",\n\t\t// \tSeparator: \"|\",\n\t\t// \tExpected:  \"12\",\n\t\t// },\n\t\t{\n\t\t\tCase:       \"Defaults\",\n\t\t\tPipeStatus: \"0 127 0\",\n\t\t\tTemplate:   \"{{ .Code }}\",\n\t\t\tSeparator:  \"|\",\n\t\t\tExpected:   \"0|127|0\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"No integer\",\n\t\t\tPipeStatus: \"0 err 0\",\n\t\t\tTemplate:   \"{{ .Code }}\",\n\t\t\tSeparator:  \"|\",\n\t\t\tExpected:   \"0|err|0\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"Incorrect template\",\n\t\t\tPipeStatus: \"1 0 0\",\n\t\t\tTemplate:   \"{{}}\",\n\t\t\tSeparator:  \"|\",\n\t\t\tExpected:   \"1|0|0\",\n\t\t},\n\t\t{\n\t\t\tCase:       \"Advanced template\",\n\t\t\tPipeStatus: \"1 0 0\",\n\t\t\tTemplate:   \"{{ if eq .Code 0 }}\\uf058{{ else }}\\uf071{{ end }}\",\n\t\t\tSeparator:  \"|\",\n\t\t\tExpected:   \"\\uf071|\\uf058|\\uf058\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tStatusTemplate:  tc.Template,\n\t\t\tStatusSeparator: tc.Separator,\n\t\t}\n\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(shell.GENERIC)\n\n\t\ts := &Status{}\n\t\ts.Init(props, env)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tCode: tc.Status,\n\t\t\t},\n\t\t}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tassert.Equal(t, tc.Expected, s.formatStatus(tc.Status, tc.PipeStatus), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/strava.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// StravaAPI is a wrapper around http.Oauth\ntype StravaAPI interface {\n\tGetActivities() ([]*StravaData, error)\n}\n\ntype stravaAPI struct {\n\thttp.OAuthRequest\n}\n\nfunc (s *stravaAPI) GetActivities() ([]*StravaData, error) {\n\turl := \"https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1\"\n\treturn http.OauthResult[[]*StravaData](&s.OAuthRequest, url, nil)\n}\n\n// segment struct, makes templating easier\ntype Strava struct {\n\tBase\n\n\tapi   StravaAPI\n\tIcon  string\n\tAgo   string\n\tError string\n\tURL   string\n\tStravaData\n\tHours        int\n\tAuthenticate bool\n}\n\nconst (\n\tRideIcon            options.Option = \"ride_icon\"\n\tRunIcon             options.Option = \"run_icon\"\n\tSkiingIcon          options.Option = \"skiing_icon\"\n\tWorkOutIcon         options.Option = \"workout_icon\"\n\tUnknownActivityIcon options.Option = \"unknown_activity_icon\"\n\n\tStravaAccessTokenKey  = \"strava_access_token\"\n\tStravaRefreshTokenKey = \"strava_refresh_token\"\n\n\tnoActivitiesFound = \"No activities found\"\n)\n\n// StravaData struct contains the API data\ntype StravaData struct {\n\tStartDate            time.Time `json:\"start_date\"`\n\tType                 string    `json:\"type\"`\n\tName                 string    `json:\"name\"`\n\tID                   int       `json:\"id\"`\n\tDistance             float64   `json:\"distance\"`\n\tDuration             float64   `json:\"moving_time\"`\n\tAverageWatts         float64   `json:\"average_watts\"`\n\tWeightedAverageWatts float64   `json:\"weighted_average_watts\"`\n\tAverageHeartRate     float64   `json:\"average_heartrate\"`\n\tMaxHeartRate         float64   `json:\"max_heartrate\"`\n\tKudosCount           int       `json:\"kudos_count\"`\n\tDeviceWatts          bool      `json:\"device_watts\"`\n}\n\nfunc (s *Strava) Template() string {\n\treturn \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Ago }}{{ end }} \"\n}\n\nfunc (s *Strava) Enabled() bool {\n\ts.initAPI()\n\n\tdata, err := s.api.GetActivities()\n\tif err == nil && len(data) > 0 {\n\t\ts.StravaData = *data[0]\n\t\ts.Icon = s.getActivityIcon()\n\t\ts.Hours = s.getHours()\n\t\ts.Ago = s.getAgo()\n\t\ts.URL = fmt.Sprintf(\"https://www.strava.com/activities/%d\", s.ID)\n\t\treturn true\n\t}\n\tif err == nil && len(data) == 0 {\n\t\ts.Error = noActivitiesFound\n\t\treturn true\n\t}\n\tif _, s.Authenticate = err.(*http.OAuthError); s.Authenticate {\n\t\ts.Error = err.(*http.OAuthError).Error()\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (s *Strava) initAPI() {\n\tif s.api != nil {\n\t\treturn\n\t}\n\n\toauth := &http.OAuthRequest{\n\t\tAccessTokenKey:  StravaAccessTokenKey,\n\t\tRefreshTokenKey: StravaRefreshTokenKey,\n\t\tSegmentName:     \"strava\",\n\t\tAccessToken:     s.options.Template(options.AccessToken, \"\", s),\n\t\tRefreshToken:    s.options.Template(options.RefreshToken, \"\", s),\n\t\tRequest: http.Request{\n\t\t\tEnv:         s.env,\n\t\t\tHTTPTimeout: s.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout),\n\t\t},\n\t}\n\n\ts.api = &stravaAPI{\n\t\tOAuthRequest: *oauth,\n\t}\n}\n\nfunc (s *Strava) getHours() int {\n\thours := time.Since(s.StartDate).Hours()\n\treturn int(math.Floor(hours))\n}\n\nfunc (s *Strava) getAgo() string {\n\tif s.Hours > 24 {\n\t\tdays := int32(math.Floor(float64(s.Hours) / float64(24)))\n\t\treturn fmt.Sprintf(\"%d\", days) + string('d')\n\t}\n\treturn fmt.Sprintf(\"%d\", s.Hours) + string(\"h\")\n}\n\nfunc (s *Strava) getActivityIcon() string {\n\tswitch s.Type {\n\tcase \"VirtualRide\":\n\t\tfallthrough\n\tcase \"Ride\":\n\t\treturn s.options.String(RideIcon, \"\\uf206\")\n\tcase \"Run\":\n\t\treturn s.options.String(RunIcon, \"\\ue213\")\n\tcase \"NordicSki\":\n\tcase \"AlpineSki\":\n\tcase \"BackcountrySki\":\n\t\treturn s.options.String(SkiingIcon, \"\\ue213\")\n\tcase \"WorkOut\":\n\t\treturn s.options.String(WorkOutIcon, \"\\ue213\")\n\tdefault:\n\t\treturn s.options.String(UnknownActivityIcon, \"\\ue213\")\n\t}\n\treturn s.options.String(UnknownActivityIcon, \"\\ue213\")\n}\n"
  },
  {
    "path": "src/segments/strava_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\ntype mockedStravaAPI struct {\n\ttestify_.Mock\n}\n\nfunc (s *mockedStravaAPI) GetActivities() ([]*StravaData, error) {\n\targs := s.Called()\n\treturn args.Get(0).([]*StravaData), args.Error(1)\n}\n\nfunc TestStravaSegment(t *testing.T) {\n\th, _ := time.ParseDuration(\"6h\")\n\tsixHoursAgo := time.Now().Add(-h)\n\th, _ = time.ParseDuration(\"100h\")\n\tfourDaysAgo := time.Now().Add(-h)\n\n\tcases := []struct {\n\t\tAPIError        error\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tStravaData      []*StravaData\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase: \"Ride 6\",\n\t\t\tStravaData: []*StravaData{\n\t\t\t\t{\n\t\t\t\t\tType:      \"Ride\",\n\t\t\t\t\tStartDate: sixHoursAgo,\n\t\t\t\t\tName:      \"Sesongens første på tjukkas\",\n\t\t\t\t\tDistance:  16144.0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate:        \"{{.Ago}} {{.Icon}}\",\n\t\t\tExpectedString:  \"6h \\uf206\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Run 100\",\n\t\t\tStravaData: []*StravaData{\n\t\t\t\t{\n\t\t\t\t\tType:      \"Run\",\n\t\t\t\t\tStartDate: fourDaysAgo,\n\t\t\t\t\tName:      \"Sesongens første på tjukkas\",\n\t\t\t\t\tDistance:  16144.0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate:        \"{{.Ago}} {{.Icon}}\",\n\t\t\tExpectedString:  \"4d \\ue213\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Error in retrieving data\",\n\t\t\tAPIError:        errors.New(\"Something went wrong\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Empty array\",\n\t\t\tStravaData:      []*StravaData{},\n\t\t\tExpectedString:  noActivitiesFound,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase: \"Faulty template\",\n\t\t\tStravaData: []*StravaData{\n\t\t\t\t{\n\t\t\t\t\tType:      \"Run\",\n\t\t\t\t\tStartDate: fourDaysAgo,\n\t\t\t\t\tName:      \"Sesongens første på tjukkas\",\n\t\t\t\t\tDistance:  16144.0,\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate:        \"{{.Ago}}{{.Burp}}\",\n\t\t\tExpectedString:  template.IncorrectTemplate,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tapi := &mockedStravaAPI{}\n\t\tapi.On(\"GetActivities\").Return(tc.StravaData, tc.APIError)\n\n\t\tstrava := &Strava{\n\t\t\tapi: api,\n\t\t}\n\t\tstrava.Init(options.Map{}, nil)\n\n\t\tenabled := strava.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = strava.Template()\n\t\t}\n\n\t\tvar got = renderTemplate(&mock.Environment{}, tc.Template, strava)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/svelte.go",
    "content": "package segments\n\ntype Svelte struct {\n\tLanguage\n}\n\nfunc (s *Svelte) Template() string {\n\treturn languageTemplate\n}\n\nfunc (s *Svelte) Enabled() bool {\n\ts.extensions = []string{\"svelte.config.js\"}\n\ts.tooling = map[string]*cmd{\n\t\t\"svelte\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\tgetVersion: s.getVersion,\n\t\t},\n\t}\n\ts.defaultTooling = []string{\"svelte\"}\n\ts.versionURLTemplate = \"https://github.com/sveltejs/svelte/releases/tag/svelte%40{{.Full}}\"\n\n\treturn s.Language.Enabled()\n}\n\nfunc (s *Svelte) getVersion() (string, error) {\n\treturn s.nodePackageVersion(\"svelte\")\n}\n"
  },
  {
    "path": "src/segments/svn.go",
    "content": "package segments\n\nimport (\n\t\"path\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n)\n\n// SvnStatus represents part of the status of a Svn repository\ntype SvnStatus struct {\n\tScmStatus\n}\n\nfunc (s *SvnStatus) add(code string) {\n\tswitch code {\n\tcase \"?\":\n\t\ts.Untracked++\n\tcase \"C\":\n\t\ts.Conflicted++\n\tcase \"D\":\n\t\ts.Deleted++\n\tcase \"A\":\n\t\ts.Added++\n\tcase \"M\":\n\t\ts.Modified++\n\tcase \"R\", \"!\":\n\t\ts.Moved++\n\t}\n}\n\nfunc (s *SvnStatus) HasConflicts() bool {\n\treturn s.Conflicted > 0\n}\n\nconst (\n\tSVNCOMMAND = \"svn\"\n)\n\ntype Svn struct {\n\tWorking *SvnStatus\n\tBranch  string\n\tScm\n\tBaseRev int\n}\n\nfunc (s *Svn) Template() string {\n\treturn \" \\ue0a0{{.Branch}} r{{.BaseRev}} {{.Working.String}} \"\n}\n\nfunc (s *Svn) Enabled() bool {\n\tif !s.shouldDisplay() {\n\t\treturn false\n\t}\n\n\ts.setSvnStatus()\n\n\treturn true\n}\n\nfunc (s *Svn) CacheKey() (string, bool) {\n\tdir, err := s.env.HasParentFilePath(\".svn\", true)\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\n\treturn dir.Path, true\n}\n\nfunc (s *Svn) shouldDisplay() bool {\n\tif !s.hasCommand(SVNCOMMAND) {\n\t\treturn false\n\t}\n\n\tSvndir, err := s.env.HasParentFilePath(\".svn\", false)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tif Svndir.IsDir {\n\t\ts.mainSCMDir = Svndir.Path\n\t\ts.scmDir = Svndir.Path\n\t\t// convert the worktree file path to a windows one when in a WSL shared folder\n\t\ts.repoRootDir = strings.TrimSuffix(s.convertToWindowsPath(Svndir.Path), \"/.svn\")\n\t\treturn true\n\t}\n\n\t// handle worktree\n\ts.scmDir = Svndir.Path\n\tdirPointer := strings.Trim(s.env.FileContent(Svndir.Path), \" \\r\\n\")\n\tmatches := regex.FindNamedRegexMatch(`^Svndir: (?P<dir>.*)$`, dirPointer)\n\tif matches != nil && matches[\"dir\"] != \"\" {\n\t\t// if we open a worktree file in a WSL shared folder, we have to convert it back\n\t\t// to the mounted path\n\t\ts.mainSCMDir = s.convertToLinuxPath(matches[\"dir\"])\n\t}\n\treturn false\n}\n\nfunc (s *Svn) setSvnStatus() {\n\ts.BaseRev, _ = strconv.Atoi(s.getSvnCommandOutput(\"info\", \"--show-item\", \"revision\"))\n\n\tbranch := s.getSvnCommandOutput(\"info\", \"--show-item\", \"relative-url\")\n\tif len(branch) > 2 {\n\t\ts.Branch = branch[2:]\n\t}\n\n\tstatusFormats := s.options.KeyValueMap(StatusFormats, map[string]string{})\n\ts.Working = &SvnStatus{ScmStatus: ScmStatus{Formats: statusFormats}}\n\n\tdisplayStatus := s.options.Bool(FetchStatus, false)\n\tif !displayStatus {\n\t\treturn\n\t}\n\n\tchanges := s.getSvnCommandOutput(\"status\")\n\tif changes == \"\" {\n\t\treturn\n\t}\n\tlines := strings.SplitSeq(changes, \"\\n\")\n\tfor line := range lines {\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\t// element is the element from someSlice for where we are\n\t\ts.Working.add(line[0:1])\n\t}\n}\n\nfunc (s *Svn) Repo() string {\n\t// Get the repository name as the last path element of the repository root URL\n\trepo := s.getSvnCommandOutput(\"info\", \"--show-item\", \"repos-root-url\")\n\tbase := path.Base(repo)\n\n\tif base == \".\" {\n\t\treturn \"\"\n\t}\n\n\treturn base\n}\n\nfunc (s *Svn) getSvnCommandOutput(command string, args ...string) string {\n\targs = append([]string{command, s.repoRootDir}, args...)\n\tval, err := s.env.RunCommand(s.command, args...)\n\tif err != nil {\n\t\treturn \"\"\n\t}\n\treturn strings.TrimSpace(val)\n}\n"
  },
  {
    "path": "src/segments/svn_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSvnEnabledToolNotFound(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"svn\").Return(false)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"IsWsl\").Return(false)\n\n\ts := &Svn{}\n\ts.Init(options.Map{}, env)\n\n\tassert.False(t, s.Enabled())\n}\n\nfunc TestSvnEnabledInWorkingDirectory(t *testing.T) {\n\tfileInfo := &runtime.FileInfo{\n\t\tPath:         \"/dir/hello\",\n\t\tParentFolder: \"/dir\",\n\t\tIsDir:        true,\n\t}\n\tenv := new(mock.Environment)\n\tenv.On(\"InWSLSharedDrive\").Return(false)\n\tenv.On(\"HasCommand\", \"svn\").Return(true)\n\tenv.On(\"GOOS\").Return(\"\")\n\tenv.On(\"FileContent\", \"/dir/hello/trunk\").Return(\"\")\n\tenv.MockSvnCommand(fileInfo.Path, \"\", \"info\", \"--tags\", \"--exact-match\")\n\tenv.On(\"RunCommand\", \"svn\", []string{\"info\", \"/dir/hello\", \"--show-item\", \"revision\"}).Return(\"\", nil)\n\tenv.On(\"RunCommand\", \"svn\", []string{\"info\", \"/dir/hello\", \"--show-item\", \"relative-url\"}).Return(\"\", nil)\n\tenv.On(\"IsWsl\").Return(false)\n\tenv.On(\"HasParentFilePath\", \".svn\", false).Return(fileInfo, nil)\n\n\ts := &Svn{}\n\ts.Init(options.Map{}, env)\n\n\tassert.True(t, s.Enabled())\n\tassert.Equal(t, fileInfo.Path, s.mainSCMDir)\n\tassert.Equal(t, fileInfo.Path, s.repoRootDir)\n}\n\nfunc TestSvnTemplateString(t *testing.T) {\n\tcases := []struct {\n\t\tSvn      *Svn\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{\n\t\t\tCase:     \"Default template\",\n\t\t\tExpected: \"\\ue0a0trunk r2 ?9 +2 ~3 -7 >13 x5 !1\",\n\t\t\tTemplate: \" \\ue0a0{{.Branch}} r{{.BaseRev}} {{.Working.String}} \",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tBaseRev: 2,\n\t\t\t\tWorking: &SvnStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tUntracked:  9,\n\t\t\t\t\t\tAdded:      2,\n\t\t\t\t\t\tConflicted: 1,\n\t\t\t\t\t\tDeleted:    7,\n\t\t\t\t\t\tModified:   3,\n\t\t\t\t\t\tMoved:      13,\n\t\t\t\t\t\tUnmerged:   5,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Only Branch name\",\n\t\t\tExpected: \"trunk\",\n\t\t\tTemplate: \"{{ .Branch }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tBaseRev: 2,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working area changes\",\n\t\t\tExpected: \"trunk \\uF044 +2 ~3\",\n\t\t\tTemplate: \"{{ .Branch }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch: \"trunk\",\n\t\t\t\tWorking: &SvnStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No working area changes (using changed flag)\",\n\t\t\tExpected: \"trunk\",\n\t\t\tTemplate: \"{{ .Branch }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tWorking: &SvnStatus{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No working area changes\",\n\t\t\tExpected: \"trunk\",\n\t\t\tTemplate: \"{{ .Branch }}{{ .Working.String }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tWorking: &SvnStatus{},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Base revision with Working changes\",\n\t\t\tExpected: \"trunk - 2 \\uF044 +2 ~3\",\n\t\t\tTemplate: \"{{ .Branch }} - {{ .BaseRev }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tBaseRev: 2,\n\t\t\t\tWorking: &SvnStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:    2,\n\t\t\t\t\t\tModified: 3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Working and staging area changes with separator and stash count\",\n\t\t\tExpected: \"trunk CONFLICTED \\uF044 +2 ~3 !7\",\n\t\t\tTemplate: \"{{ .Branch }}{{ if .Working.HasConflicts }} CONFLICTED{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n\t\t\tSvn: &Svn{\n\t\t\t\tBranch:  \"trunk\",\n\t\t\t\tBaseRev: 2,\n\t\t\t\tWorking: &SvnStatus{\n\t\t\t\t\tScmStatus: ScmStatus{\n\t\t\t\t\t\tAdded:      2,\n\t\t\t\t\t\tModified:   3,\n\t\t\t\t\t\tConflicted: 7,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\t\tenv := new(mock.Environment)\n\t\ttc.Svn.env = env\n\t\ttc.Svn.options = props\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Svn), tc.Case)\n\t}\n}\n\nfunc TestSetSvnStatus(t *testing.T) {\n\tcases := []struct {\n\t\tCase              string\n\t\tStatusOutput      string\n\t\tRefOutput         string\n\t\tBranchOutput      string\n\t\tExpectedWorking   *SvnStatus\n\t\tExpectedBranch    string\n\t\tExpectedRef       int\n\t\tExpectedConflicts bool\n\t\tExpectedChanged   bool\n\t}{\n\t\t{\n\t\t\tCase: \"changed\",\n\t\t\tStatusOutput: `\n?       Untracked.File\n!       Missing.File\nA       FileHasBeen.Added\nD       FileMarkedAs.Deleted\nM       Modified.File\nC       Conflicted.File\nR       Moved.File`,\n\t\t\tExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{\n\t\t\t\tModified:   1,\n\t\t\t\tAdded:      1,\n\t\t\t\tDeleted:    1,\n\t\t\t\tMoved:      2,\n\t\t\t\tUntracked:  1,\n\t\t\t\tConflicted: 1,\n\t\t\t\tFormats:    map[string]string{},\n\t\t\t}},\n\t\t\tRefOutput:         \"1133\",\n\t\t\tExpectedRef:       1133,\n\t\t\tBranchOutput:      \"^/trunk\",\n\t\t\tExpectedBranch:    \"trunk\",\n\t\t\tExpectedChanged:   true,\n\t\t\tExpectedConflicts: true,\n\t\t},\n\t\t{\n\t\t\tCase:         \"conflict\",\n\t\t\tStatusOutput: `C       build.cake`,\n\t\t\tExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{\n\t\t\t\tConflicted: 1,\n\t\t\t\tFormats:    map[string]string{},\n\t\t\t}},\n\t\t\tExpectedChanged:   true,\n\t\t\tExpectedConflicts: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no change\",\n\t\t\tExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{Formats: map[string]string{}}},\n\t\t\tExpectedChanged: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"not an integer ref\",\n\t\t\tExpectedWorking: &SvnStatus{ScmStatus: ScmStatus{Formats: map[string]string{}}},\n\t\t\tExpectedChanged: false,\n\t\t\tRefOutput:       \"not an integer\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tfileInfo := &runtime.FileInfo{\n\t\t\tPath:         \"/dir/hello\",\n\t\t\tParentFolder: \"/dir\",\n\t\t\tIsDir:        true,\n\t\t}\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"InWSLSharedDrive\").Return(false)\n\t\tenv.On(\"IsWsl\").Return(false)\n\t\tenv.On(\"HasCommand\", \"svn\").Return(true)\n\t\tenv.On(\"GOOS\").Return(\"\")\n\t\tenv.On(\"FileContent\", \"/dir/hello/trunk\").Return(\"\")\n\t\tenv.MockSvnCommand(fileInfo.Path, \"\", \"info\", \"--tags\", \"--exact-match\")\n\t\tenv.On(\"HasParentFilePath\", \".svn\", false).Return(fileInfo, nil)\n\t\tenv.On(\"RunCommand\", \"svn\", []string{\"info\", \"\", \"--show-item\", \"revision\"}).Return(tc.RefOutput, nil)\n\t\tenv.On(\"RunCommand\", \"svn\", []string{\"info\", \"\", \"--show-item\", \"relative-url\"}).Return(tc.BranchOutput, nil)\n\t\tenv.On(\"RunCommand\", \"svn\", []string{\"status\", \"\"}).Return(tc.StatusOutput, nil)\n\n\t\tprops := options.Map{\n\t\t\tFetchStatus: true,\n\t\t}\n\n\t\ts := &Svn{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: SVNCOMMAND,\n\t\t\t},\n\t\t}\n\t\ts.Init(props, env)\n\n\t\ts.setSvnStatus()\n\t\tif tc.ExpectedWorking == nil {\n\t\t\ttc.ExpectedWorking = &SvnStatus{}\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedWorking, s.Working, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedRef, s.BaseRev, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedBranch, s.Branch, tc.Case)\n\t\tassert.Equal(t, tc.ExpectedChanged, s.Working.Changed(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedConflicts, s.Working.HasConflicts(), tc.Case)\n\t}\n}\n\nfunc TestRepo(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tRepo     string\n\t\tExpected string\n\t}{\n\t\t{\n\t\t\tCase:     \"No repo\",\n\t\t\tRepo:     \"\",\n\t\t\tExpected: \"\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Repo with trailing slash\",\n\t\t\tRepo:     \"http://example.com/\",\n\t\t\tExpected: \"example.com\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Repo without trailing slash\",\n\t\t\tRepo:     \"http://example.com\",\n\t\t\tExpected: \"example.com\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Repo with a path\",\n\t\t\tRepo:     \"http://example.com/test/repo\",\n\t\t\tExpected: \"repo\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"RunCommand\", \"svn\", []string{\"info\", \"\", \"--show-item\", \"repos-root-url\"}).Return(tc.Repo, nil)\n\n\t\ts := &Svn{\n\t\t\tScm: Scm{\n\t\t\t\tcommand: SVNCOMMAND,\n\t\t\t},\n\t\t}\n\t\ts.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.Expected, s.Repo(), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/swift.go",
    "content": "package segments\n\ntype Swift struct {\n\tLanguage\n}\n\nfunc (s *Swift) Template() string {\n\treturn languageTemplate\n}\n\nfunc (s *Swift) Enabled() bool {\n\ts.extensions = []string{\"*.swift\", \"*.SWIFT\", \"Podfile\"}\n\ts.tooling = map[string]*cmd{\n\t\t\"swift\": {\n\t\t\texecutable: \"swift\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Swift version (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+)((.|-)(?P<patch>[0-9]+|dev))?))`,\n\t\t},\n\t}\n\ts.defaultTooling = []string{\"swift\"}\n\ts.versionURLTemplate = \"https://github.com/apple/swift/releases/tag/swift-{{ .Full }}-RELEASE\"\n\n\treturn s.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/swift_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSwift(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"Swift 5.5.3\", ExpectedString: \"5.5.3\", Version: \"Swift version 5.5.3 (swift-5.5.3-RELEASE)\"},\n\t\t{Case: \"Swift 5.5.3 on Windows\", ExpectedString: \"5.5.3\", Version: \"compnerd.org Swift version 5.5.3 (swift-5.5.3-RELEASE)\"},\n\t\t{Case: \"Swift 5.5.3 on Mac\", ExpectedString: \"5.5.3\", Version: \"Apple Swift version 5.5.3 (swift-5.5.3-RELEASE)\"},\n\t\t{Case: \"Swift 5.5\", ExpectedString: \"5.5\", Version: \"Swift version 5.5 (swift-5.5-RELEASE)\"},\n\t\t{Case: \"Swift 5.6-dev\", ExpectedString: \"5.6-dev\", Version: \"Swift version 5.6-dev (LLVM 62b900d3d0d5be9, Swift ce64fe8867792d4)\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"swift\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.swift\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\ts := &Swift{}\n\t\ts.Init(props, env)\n\t\tassert.True(t, s.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, s.Template(), s), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/sysinfo.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype SystemInfo struct {\n\tBase\n\n\truntime.SystemInfo\n\tPrecision int\n}\n\nconst (\n\t// Precision number of decimal places to show\n\tPrecision options.Option = \"precision\"\n)\n\nfunc (s *SystemInfo) Template() string {\n\treturn \" {{ round .PhysicalPercentUsed .Precision }} \"\n}\n\nfunc (s *SystemInfo) Enabled() bool {\n\ts.Precision = s.options.Int(Precision, 2)\n\n\tsysInfo, err := s.env.SystemInfo()\n\tif err != nil {\n\t\treturn false\n\t}\n\n\ts.SystemInfo = *sysInfo\n\n\tif s.PhysicalPercentUsed == 0 && s.SwapPercentUsed == 0 {\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/sysinfo_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestSysInfo(t *testing.T) {\n\tcases := []struct {\n\t\tError          error\n\t\tCase           string\n\t\tExpectedString string\n\t\tTemplate       string\n\t\tSysInfo        runtime.SystemInfo\n\t\tPrecision      int\n\t\tExpectDisabled bool\n\t}{\n\t\t{\n\t\t\tCase:           \"Error\",\n\t\t\tExpectDisabled: true,\n\t\t\tError:          errors.New(\"error\"),\n\t\t},\n\t\t{\n\t\t\tCase:           \"physical mem\",\n\t\t\tExpectedString: \"50\",\n\t\t\tSysInfo: runtime.SystemInfo{\n\t\t\t\tMemory: runtime.Memory{\n\t\t\t\t\tPhysicalPercentUsed: 50,\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate: \"{{ round .PhysicalPercentUsed .Precision }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"physical mem 2 digits\",\n\t\t\tExpectedString: \"60.51\",\n\t\t\tSysInfo: runtime.SystemInfo{\n\t\t\t\tMemory: runtime.Memory{\n\t\t\t\t\tPhysicalPercentUsed: 60.51,\n\t\t\t\t},\n\t\t\t},\n\t\t\tPrecision: 2,\n\t\t\tTemplate:  \"{{ round .PhysicalPercentUsed .Precision }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"physical meme rounded\",\n\t\t\tExpectedString: \"61\",\n\t\t\tSysInfo: runtime.SystemInfo{\n\t\t\t\tMemory: runtime.Memory{\n\t\t\t\t\tPhysicalPercentUsed: 61,\n\t\t\t\t},\n\t\t\t},\n\t\t\tTemplate: \"{{ round .PhysicalPercentUsed .Precision }}\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"load\",\n\t\t\tExpectedString: \"0.22 0.12 0\",\n\t\t\tPrecision:      2,\n\t\t\tTemplate:       \"{{ round .Load1 .Precision }} {{round .Load5 .Precision }} {{round .Load15 .Precision }}\",\n\t\t\tSysInfo:        runtime.SystemInfo{Load1: 0.22, Load5: 0.12, Load15: 0},\n\t\t},\n\t\t{\n\t\t\tCase:           \"not enabled\",\n\t\t\tExpectDisabled: true,\n\t\t\tSysInfo: runtime.SystemInfo{\n\t\t\t\tMemory: runtime.Memory{\n\t\t\t\t\tPhysicalPercentUsed: 0,\n\t\t\t\t\tSwapPercentUsed:     0,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:           \"accurate memory percentage\",\n\t\t\tExpectedString: \"36.96\",\n\t\t\tSysInfo: runtime.SystemInfo{\n\t\t\t\tMemory: runtime.Memory{\n\t\t\t\t\tPhysicalPercentUsed: 36.96,\n\t\t\t\t},\n\t\t\t},\n\t\t\tPrecision: 2,\n\t\t\tTemplate:  \"{{ round .PhysicalPercentUsed .Precision }}\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"SystemInfo\").Return(&tc.SysInfo, tc.Error)\n\t\tsysInfo := &SystemInfo{}\n\t\tprops := options.Map{\n\t\t\tPrecision: tc.Precision,\n\t\t}\n\t\tsysInfo.Init(props, env)\n\t\tenabled := sysInfo.Enabled()\n\t\tif tc.ExpectDisabled {\n\t\t\tassert.Equal(t, false, enabled, tc.Case)\n\t\t} else {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, sysInfo), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/talosctl.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\tyaml \"go.yaml.in/yaml/v3\"\n)\n\ntype TalosCTL struct {\n\tBase\n\n\tContext string `yaml:\"context\"`\n}\n\nfunc (t *TalosCTL) Template() string {\n\treturn \" {{ .Context}} \"\n}\n\nfunc (t *TalosCTL) Enabled() bool {\n\tcfgDir := filepath.Join(t.env.Home(), \".talos\")\n\tconfigFile, err := t.getActiveConfig(cfgDir)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\terr = yaml.Unmarshal([]byte(configFile), t)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\n\tif t.Context == \"\" {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (t *TalosCTL) getActiveConfig(cfgDir string) (string, error) {\n\tactiveConfigFile := filepath.Join(cfgDir, \"config\")\n\tactiveConfigData := t.env.FileContent(activeConfigFile)\n\tif activeConfigData == \"\" {\n\t\treturn \"\", errors.New(\"no active config found\")\n\t}\n\treturn activeConfigData, nil\n}\n"
  },
  {
    "path": "src/segments/talosctl_test.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTalosctlSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase            string\n\t\tActiveConfig    string\n\t\tExpectedString  string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"happy path\",\n\t\t\tExpectedEnabled: true,\n\t\t\tActiveConfig:    \"context: context-name\",\n\t\t\tExpectedString:  \"context-name\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"no active config\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"empty config\",\n\t\t\tActiveConfig:    \"\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"bad config\",\n\t\t\tActiveConfig:    \"other-yaml: not-expected\",\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(\"home\")\n\t\tfcPath := filepath.Join(\"home\", \".talos\", \"config\")\n\t\tenv.On(\"FileContent\", fcPath).Return(tc.ActiveConfig)\n\n\t\ttalos := TalosCTL{}\n\t\ttalos.Init(options.Map{}, env)\n\n\t\ttalos.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, talos.Enabled())\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, talos.Template(), talos), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestGetTalosctlActiveConfig(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tActiveConfig   string\n\t\tExpectedString string\n\t\tExpectedError  string\n\t}{\n\t\t{\n\t\t\tCase:           \"happy path\",\n\t\t\tActiveConfig:   \"context: context-name\",\n\t\t\tExpectedString: \"context: context-name\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"no active config\",\n\t\t\tActiveConfig:  \"\",\n\t\t\tExpectedError: \"no active config found\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Home\").Return(\"home\")\n\t\tconfigPath := filepath.Join(\"home\", \".talos\")\n\t\tcontentPath := filepath.Join(configPath, \"config\")\n\t\tenv.On(\"FileContent\", contentPath).Return(tc.ActiveConfig)\n\n\t\ttalos := TalosCTL{}\n\t\ttalos.Init(options.Map{}, env)\n\n\t\tgot, err := talos.getActiveConfig(configPath)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t\tif len(tc.ExpectedError) > 0 {\n\t\t\tassert.EqualError(t, err, tc.ExpectedError, tc.Case)\n\t\t} else {\n\t\t\tassert.NoError(t, err, tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/taskwarrior.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\n\tc \"golang.org/x/text/cases\"\n\t\"golang.org/x/text/language\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\n// Taskwarrior option constants\nconst (\n\tTaskwarriorCommand  options.Option = \"command\"\n\tTaskwarriorCommands options.Option = \"commands\"\n)\n\n// Taskwarrior displays task counts and context from Taskwarrior.\n// The Commands field is a map from capitalized command name to the raw output\n// of the corresponding Taskwarrior invocation. Each entry in the config map\n// has the command name as key and a full Taskwarrior argument string as value.\ntype Taskwarrior struct {\n\tBase\n\n\t// Commands holds the raw output of each configured command, keyed by name\n\t// with the first letter uppercased.\n\tCommands map[string]string\n}\n\nfunc (t *Taskwarrior) Template() string {\n\treturn \" \\uf4a0 {{ range $k, $v := .Commands }}{{ $k }}:{{ $v }} {{ end }}\"\n}\n\nfunc (t *Taskwarrior) Enabled() bool {\n\tcmd := t.options.String(TaskwarriorCommand, \"task\")\n\n\tif !t.env.HasCommand(cmd) {\n\t\treturn false\n\t}\n\n\tdefaultCommands := map[string]string{\n\t\t\"due\":       \"+PENDING due.before:tomorrow count\",\n\t\t\"scheduled\": \"+PENDING scheduled.before:tomorrow count\",\n\t\t\"waiting\":   \"+WAITING count\",\n\t\t\"context\":   \"_get rc.context\",\n\t}\n\n\tconfiguredCommands := t.options.KeyValueMap(TaskwarriorCommands, defaultCommands)\n\n\tt.Commands = make(map[string]string, len(configuredCommands))\n\n\tfor name, args := range configuredCommands {\n\t\tkey := c.Title(language.English).String(name)\n\t\tt.Commands[key] = t.runCommand(cmd, args)\n\t}\n\n\treturn true\n}\n\nfunc (t *Taskwarrior) runCommand(cmd, args string) string {\n\toutput, err := t.env.RunCommand(cmd, strings.Fields(args)...)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\"\n\t}\n\n\treturn strings.TrimSpace(output)\n}\n"
  },
  {
    "path": "src/segments/taskwarrior_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTaskwarrior(t *testing.T) {\n\tcases := []struct {\n\t\tConfiguredCommands map[string]string\n\t\tCommandOutputs     map[string]string\n\t\tCommandErrors      map[string]error\n\t\tExpectedCommands   map[string]string\n\t\tCase               string\n\t\tCommand            string\n\t\tHasCommand         bool\n\t\tExpectedEnabled    bool\n\t}{\n\t\t{\n\t\t\tCase:       \"happy path default commands\",\n\t\t\tHasCommand: true,\n\t\t\tCommandOutputs: map[string]string{\n\t\t\t\t\"+PENDING due.before:tomorrow count\":       \"3\",\n\t\t\t\t\"+PENDING scheduled.before:tomorrow count\": \"1\",\n\t\t\t\t\"+WAITING count\":                           \"2\",\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Due\":       \"3\",\n\t\t\t\t\"Scheduled\": \"1\",\n\t\t\t\t\"Waiting\":   \"2\",\n\t\t\t\t\"Context\":   \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:            \"no command\",\n\t\t\tHasCommand:      false,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:       \"all zeros\",\n\t\t\tHasCommand: true,\n\t\t\tCommandOutputs: map[string]string{\n\t\t\t\t\"+PENDING due.before:tomorrow count\":       \"0\",\n\t\t\t\t\"+PENDING scheduled.before:tomorrow count\": \"0\",\n\t\t\t\t\"+WAITING count\":                           \"0\",\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Due\":       \"0\",\n\t\t\t\t\"Scheduled\": \"0\",\n\t\t\t\t\"Waiting\":   \"0\",\n\t\t\t\t\"Context\":   \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:       \"custom commands only\",\n\t\t\tHasCommand: true,\n\t\t\tConfiguredCommands: map[string]string{\n\t\t\t\t\"urgent\": \"+PENDING +OVERDUE count\",\n\t\t\t},\n\t\t\tCommandOutputs: map[string]string{\n\t\t\t\t\"+PENDING +OVERDUE count\": \"5\",\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Urgent\": \"5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:       \"context command via commands map\",\n\t\t\tHasCommand: true,\n\t\t\tConfiguredCommands: map[string]string{\n\t\t\t\t\"due\":     \"+PENDING due.before:tomorrow count\",\n\t\t\t\t\"context\": \"_get rc.context\",\n\t\t\t},\n\t\t\tCommandOutputs: map[string]string{\n\t\t\t\t\"+PENDING due.before:tomorrow count\": \"3\",\n\t\t\t\t\"_get rc.context\":                    \"work\",\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Due\":     \"3\",\n\t\t\t\t\"Context\": \"work\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:       \"command error returns empty string for that command\",\n\t\t\tHasCommand: true,\n\t\t\tConfiguredCommands: map[string]string{\n\t\t\t\t\"due\": \"+PENDING due.before:tomorrow count\",\n\t\t\t},\n\t\t\tCommandErrors: map[string]error{\n\t\t\t\t\"+PENDING due.before:tomorrow count\": errors.New(\"command failed\"),\n\t\t\t},\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Due\": \"\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:    \"custom executable is used when TaskwarriorCommand is set\",\n\t\t\tCommand: \"task2\",\n\t\t\tConfiguredCommands: map[string]string{\n\t\t\t\t\"due\": \"+PENDING due.before:tomorrow count\",\n\t\t\t},\n\t\t\tCommandOutputs: map[string]string{\n\t\t\t\t\"+PENDING due.before:tomorrow count\": \"7\",\n\t\t\t},\n\t\t\tHasCommand:      true,\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCommands: map[string]string{\n\t\t\t\t\"Due\": \"7\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tenv := new(mock.Environment)\n\n\t\t\tcmd := tc.Command\n\t\t\tif cmd == \"\" {\n\t\t\t\tcmd = \"task\"\n\t\t\t}\n\n\t\t\tenv.On(\"HasCommand\", cmd).Return(tc.HasCommand)\n\n\t\t\tconfiguredCommands := tc.ConfiguredCommands\n\t\t\tif configuredCommands == nil && tc.HasCommand {\n\t\t\t\t// default commands\n\t\t\t\tconfiguredCommands = map[string]string{\n\t\t\t\t\t\"due\":       \"+PENDING due.before:tomorrow count\",\n\t\t\t\t\t\"scheduled\": \"+PENDING scheduled.before:tomorrow count\",\n\t\t\t\t\t\"waiting\":   \"+WAITING count\",\n\t\t\t\t\t\"context\":   \"_get rc.context\",\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor _, args := range configuredCommands {\n\t\t\t\tsplitArgs := splitTaskArgs(args)\n\t\t\t\tvar output string\n\t\t\t\tvar err error\n\t\t\t\tif tc.CommandOutputs != nil {\n\t\t\t\t\toutput = tc.CommandOutputs[args]\n\t\t\t\t}\n\t\t\t\tif tc.CommandErrors != nil {\n\t\t\t\t\terr = tc.CommandErrors[args]\n\t\t\t\t}\n\t\t\t\tenv.On(\"RunCommand\", cmd, splitArgs).Return(output, err)\n\t\t\t}\n\n\t\t\tprops := options.Map{}\n\t\t\tif tc.ConfiguredCommands != nil {\n\t\t\t\tprops[TaskwarriorCommands] = tc.ConfiguredCommands\n\t\t\t}\n\t\t\tif tc.Command != \"\" {\n\t\t\t\tprops[TaskwarriorCommand] = tc.Command\n\t\t\t}\n\n\t\t\ttw := &Taskwarrior{}\n\t\t\ttw.Init(props, env)\n\n\t\t\tassert.Equal(t, tc.ExpectedEnabled, tw.Enabled(), tc.Case)\n\n\t\t\tif !tc.ExpectedEnabled {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tassert.Equal(t, tc.ExpectedCommands, tw.Commands, tc.Case)\n\t\t})\n\t}\n}\n\n// splitTaskArgs splits a space-separated argument string into a slice.\nfunc splitTaskArgs(s string) []string {\n\treturn strings.Fields(s)\n}\n"
  },
  {
    "path": "src/segments/tauri.go",
    "content": "package segments\n\nimport (\n\t\"path/filepath\"\n)\n\ntype Tauri struct {\n\tLanguage\n}\n\nfunc (t *Tauri) Template() string {\n\treturn languageTemplate\n}\n\nfunc (t *Tauri) Enabled() bool {\n\tt.extensions = []string{\"tauri.conf.json\"}\n\tt.folders = []string{\"src-tauri\"}\n\tt.tooling = map[string]*cmd{\n\t\t\"tauri\": {\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t\tgetVersion: t.getVersion,\n\t\t},\n\t}\n\tt.defaultTooling = []string{\"tauri\"}\n\tt.versionURLTemplate = \"https://github.com/tauri-apps/tauri/releases/tag/tauri-v{{.Full}}\"\n\n\treturn t.Language.Enabled()\n}\n\nfunc (t *Tauri) getVersion() (string, error) {\n\treturn t.nodePackageVersion(filepath.Join(\"@tauri-apps\", \"api\"))\n}\n"
  },
  {
    "path": "src/segments/terraform.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"path/filepath\"\n\t\"slices\"\n\n\t\"github.com/hashicorp/hcl/v2/gohcl\"\n\t\"github.com/hashicorp/hcl/v2/hclparse\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tCommand options.Option = \"command\"\n)\n\ntype Terraform struct {\n\tBase\n\n\tTerraformBlock\n\tWorkspaceName string\n}\n\nfunc (tf *Terraform) Template() string {\n\treturn \" {{ .WorkspaceName }}{{ if .Version }} {{ .Version }}{{ end }} \"\n}\n\ntype TerraFormConfig struct {\n\tTerraform *TerraformBlock `hcl:\"terraform,block\"`\n}\n\ntype TerraformBlock struct {\n\tVersion *string `hcl:\"required_version\" json:\"terraform_version\"`\n}\n\nfunc (tf *Terraform) Enabled() bool {\n\tcmd := tf.options.String(Command, \"terraform\")\n\tfetchVersion := tf.options.Bool(options.FetchVersion, false)\n\n\tif !tf.env.HasCommand(cmd) || !tf.inContext(fetchVersion) {\n\t\treturn false\n\t}\n\n\ttf.WorkspaceName, _ = tf.env.RunCommand(cmd, \"workspace\", \"show\")\n\tif !fetchVersion {\n\t\treturn true\n\t}\n\n\tif err := tf.setVersionFromTfFiles(); err == nil {\n\t\treturn true\n\t}\n\n\ttf.setVersionFromTfStateFile()\n\treturn true\n}\n\nfunc (tf *Terraform) inContext(fetchVersion bool) bool {\n\tterraformFolder := filepath.Join(tf.env.Pwd(), \".terraform\")\n\n\tif tf.env.HasFolder(terraformFolder) {\n\t\treturn true\n\t}\n\n\tfiles := []string{\".tf\", \".tfplan\", \".tfstate\"}\n\tif slices.ContainsFunc(files, tf.env.HasFiles) {\n\t\treturn true\n\t}\n\n\tif !fetchVersion {\n\t\treturn false\n\t}\n\n\tversionFiles := []string{\"versions.tf\", \"main.tf\", \"terraform.tfstate\"}\n\treturn slices.ContainsFunc(versionFiles, tf.env.HasFiles)\n}\n\nfunc (tf *Terraform) setVersionFromTfFiles() error {\n\tfiles := []string{\"versions.tf\", \"main.tf\"}\n\tfor _, file := range files {\n\t\tif !tf.env.HasFiles(file) {\n\t\t\tcontinue\n\t\t}\n\n\t\tparser := hclparse.NewParser()\n\t\tcontent := tf.env.FileContent(file)\n\t\thclFile, diags := parser.ParseHCL([]byte(content), file)\n\t\tif diags != nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar config TerraFormConfig\n\t\tdiags = gohcl.DecodeBody(hclFile.Body, nil, &config)\n\t\tif diags != nil || config.Terraform == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\ttf.TerraformBlock = *config.Terraform\n\t\treturn nil\n\t}\n\treturn errors.New(\"no valid terraform files found\")\n}\n\nfunc (tf *Terraform) setVersionFromTfStateFile() {\n\tfile := \"terraform.tfstate\"\n\tif !tf.env.HasFiles(file) {\n\t\treturn\n\t}\n\n\tcontent := tf.env.FileContent(file)\n\t_ = json.Unmarshal([]byte(content), &tf.TerraformBlock)\n}\n"
  },
  {
    "path": "src/segments/terraform_test.go",
    "content": "package segments\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTerraform(t *testing.T) {\n\tcases := []struct {\n\t\tCase              string\n\t\tTemplate          string\n\t\tWorkspaceName     string\n\t\tExpectedString    string\n\t\tHasTfCommand      bool\n\t\tHasTfFolder       bool\n\t\tHasTfFiles        bool\n\t\tHasTfVersionFiles bool\n\t\tHasTfStateFile    bool\n\t\tFetchVersion      bool\n\t\tExpectedEnabled   bool\n\t}{\n\t\t{\n\t\t\tCase:            \"default workspace\",\n\t\t\tExpectedString:  \"default\",\n\t\t\tExpectedEnabled: true,\n\t\t\tWorkspaceName:   \"default\",\n\t\t\tHasTfFolder:     true,\n\t\t\tHasTfCommand:    true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"no command\",\n\t\t\tExpectedString: \"\",\n\t\t\tWorkspaceName:  \"default\",\n\t\t\tHasTfFolder:    true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"no directory, no files\",\n\t\t\tExpectedString: \"\",\n\t\t\tWorkspaceName:  \"default\",\n\t\t\tHasTfCommand:   true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"no files\",\n\t\t\tExpectedString: \"\",\n\t\t\tWorkspaceName:  \"default\",\n\t\t\tHasTfCommand:   true,\n\t\t\tFetchVersion:   true,\n\t\t},\n\t\t{\n\t\t\tCase:              \"files\",\n\t\t\tExpectedString:    \">= 1.0.10\",\n\t\t\tExpectedEnabled:   true,\n\t\t\tWorkspaceName:     \"default\",\n\t\t\tTemplate:          \"{{ .Version }}\",\n\t\t\tHasTfVersionFiles: true,\n\t\t\tHasTfCommand:      true,\n\t\t\tFetchVersion:      true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"version files\",\n\t\t\tExpectedString:  \"0.12.24\",\n\t\t\tExpectedEnabled: true,\n\t\t\tWorkspaceName:   \"default\",\n\t\t\tTemplate:        \"{{ .Version }}\",\n\t\t\tHasTfStateFile:  true,\n\t\t\tHasTfCommand:    true,\n\t\t\tFetchVersion:    true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"context files\",\n\t\t\tExpectedString:  \"default\",\n\t\t\tExpectedEnabled: true,\n\t\t\tWorkspaceName:   \"default\",\n\t\t\tHasTfFiles:      true,\n\t\t\tHasTfCommand:    true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\tenv.On(\"HasCommand\", \"terraform\").Return(tc.HasTfCommand)\n\t\tenv.On(\"HasFolder\", \".terraform\").Return(tc.HasTfFolder)\n\t\tenv.On(\"HasFiles\", \".tf\").Return(tc.HasTfFiles)\n\t\tenv.On(\"HasFiles\", \".tfplan\").Return(tc.HasTfFiles)\n\t\tenv.On(\"HasFiles\", \".tfstate\").Return(tc.HasTfFiles)\n\t\tenv.On(\"Pwd\").Return(\"\")\n\t\tenv.On(\"RunCommand\", \"terraform\", []string{\"workspace\", \"show\"}).Return(tc.WorkspaceName, nil)\n\t\tenv.On(\"HasFiles\", \"versions.tf\").Return(tc.HasTfVersionFiles)\n\t\tenv.On(\"HasFiles\", \"main.tf\").Return(tc.HasTfVersionFiles)\n\t\tenv.On(\"HasFiles\", \"terraform.tfstate\").Return(tc.HasTfStateFile)\n\t\tif tc.HasTfVersionFiles {\n\t\t\tcontent, _ := os.ReadFile(\"../test/versions.tf\")\n\t\t\tenv.On(\"FileContent\", \"versions.tf\").Return(string(content))\n\t\t}\n\t\tif tc.HasTfStateFile {\n\t\t\tcontent, _ := os.ReadFile(\"../test/terraform.tfstate\")\n\t\t\tenv.On(\"FileContent\", \"terraform.tfstate\").Return(string(content))\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\toptions.FetchVersion: tc.FetchVersion,\n\t\t}\n\n\t\ttf := &Terraform{}\n\t\ttf.Init(props, env)\n\n\t\ttemplate := tc.Template\n\t\tif template == \"\" {\n\t\t\ttemplate = tf.Template()\n\t\t}\n\t\tassert.Equal(t, tc.ExpectedEnabled, tf.Enabled(), tc.Case)\n\t\tvar got = renderTemplate(env, template, tf)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/text.go",
    "content": "package segments\n\ntype Text struct {\n\tBase\n}\n\nfunc (t *Text) Template() string {\n\treturn \"  \"\n}\n\nfunc (t *Text) Enabled() bool {\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/text_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTextSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase             string\n\t\tExpectedString   string\n\t\tTemplate         string\n\t\tExpectedDisabled bool\n\t}{\n\t\t{Case: \"standard text\", ExpectedString: \"hello\", Template: \"hello\"},\n\t\t{Case: \"template text with env var\", ExpectedString: \"hello world\", Template: \"{{ .Env.HELLO }} world\"},\n\t\t{Case: \"template text with shell name\", ExpectedString: \"hello world from terminal\", Template: \"{{ .Env.HELLO }} world from {{ .Shell }}\"},\n\t\t{Case: \"template text with folder\", ExpectedString: \"hello world in posh\", Template: \"{{ .Env.HELLO }} world in {{ .Folder }}\"},\n\t\t{Case: \"template text with user\", ExpectedString: \"hello Posh\", Template: \"{{ .Env.HELLO }} {{ .UserName }}\"},\n\t\t{Case: \"empty text\", Template: \"\", ExpectedDisabled: true},\n\t\t{Case: \"empty template result\", Template: \"{{ .Env.WORLD }}\", ExpectedDisabled: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"PathSeparator\").Return(\"/\")\n\t\tenv.On(\"Getenv\", \"HELLO\").Return(\"hello\")\n\t\tenv.On(\"Getenv\", \"WORLD\").Return(\"\")\n\n\t\ttxt := &Text{}\n\t\ttxt.Init(options.Map{}, env)\n\n\t\ttemplate.Cache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tUserName: \"Posh\",\n\t\t\t\tHostName: \"MyHost\",\n\t\t\t\tShell:    \"terminal\",\n\t\t\t\tRoot:     true,\n\t\t\t\tFolder:   \"posh\",\n\t\t\t},\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, txt), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/time.go",
    "content": "package segments\n\nimport (\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Time struct {\n\tBase\n\n\tCurrentDate time.Time\n\tFormat      string\n}\n\nconst (\n\t// TimeFormat uses the reference time Mon Jan 2 15:04:05 MST 2006 to show the pattern with which to format the current time\n\tTimeFormat options.Option = \"time_format\"\n)\n\nfunc (t *Time) Template() string {\n\treturn \" {{ .CurrentDate | date .Format }} \"\n}\n\nfunc (t *Time) Enabled() bool {\n\t// if no date set, use now(unit testing)\n\tformatInput := t.options.String(TimeFormat, \"15:04:05\")\n\tt.Format = t.getTimeFormat(formatInput)\n\tif t.CurrentDate.IsZero() {\n\t\tt.CurrentDate = time.Now()\n\t}\n\n\treturn true\n}\n\nvar timeFormatLookup = map[string]string{\n\t// Maps string names to their corresponding time package constants\n\t\"Layout\":      time.Layout,      // \"01/02 03:04:05PM '06 -0700\"\n\t\"ANSIC\":       time.ANSIC,       // \"Mon Jan _2 15:04:05 2006\"\n\t\"UnixDate\":    time.UnixDate,    // \"Mon Jan _2 15:04:05 MST 2006\"\n\t\"RubyDate\":    time.RubyDate,    // \"Mon Jan 02 15:04:05 -0700 2006\"\n\t\"RFC822\":      time.RFC822,      // \"02 Jan 06 15:04 MST\"\n\t\"RFC822Z\":     time.RFC822Z,     // \"02 Jan 06 15:04 -0700\"\n\t\"RFC850\":      time.RFC850,      // \"Monday, 02-Jan-06 15:04:05 MST\"\n\t\"RFC1123\":     time.RFC1123,     // \"Mon, 02 Jan 2006 15:04:05 MST\"\n\t\"RFC1123Z\":    time.RFC1123Z,    // \"Mon, 02 Jan 2006 15:04:05 -0700\"\n\t\"RFC3339\":     time.RFC3339,     // \"2006-01-02T15:04:05Z07:00\"\n\t\"RFC3339Nano\": time.RFC3339Nano, // \"2006-01-02T15:04:05.999999999Z07:00\"\n\t\"Kitchen\":     time.Kitchen,     // \"3:04PM\"\n\t\"Stamp\":       time.Stamp,       // \"Jan _2 15:04:05\"\n\t\"StampMilli\":  time.StampMilli,  // \"Jan _2 15:04:05.000\"\n\t\"StampMicro\":  time.StampMicro,  // \"Jan _2 15:04:05.000000\"\n\t\"StampNano\":   time.StampNano,   // \"Jan _2 15:04:05.000000000\"\n\t\"DateTime\":    time.DateTime,    // \"2006-01-02 15:04:05\"\n\t\"DateOnly\":    time.DateOnly,    // \"2006-01-02\"\n\t\"TimeOnly\":    time.TimeOnly,    // \"15:04:05\"\n}\n\n// getTimeFormat returns the time format constant if the input matches a known format name,\n// otherwise returns the input unchanged\nfunc (t *Time) getTimeFormat(format string) string {\n\tif timeFormat, exists := timeFormatLookup[format]; exists {\n\t\treturn timeFormat\n\t}\n\treturn format\n}\n"
  },
  {
    "path": "src/segments/time_test.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTimeSegmentTemplate(t *testing.T) {\n\t// set date for unit test\n\tcurrentDate := time.Now()\n\tcases := []struct {\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no template\",\n\t\t\tTemplate:        \"\",\n\t\t\tExpectedString:  currentDate.Format(\"15:04:05\"),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"time only\",\n\t\t\tTemplate:        \"{{.CurrentDate | date \\\"15:04:05\\\"}}\",\n\t\t\tExpectedString:  currentDate.Format(\"15:04:05\"),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"lowercase\",\n\t\t\tTemplate:        \"{{.CurrentDate | date \\\"January 02, 2006 15:04:05\\\" | lower }}\",\n\t\t\tExpectedString:  strings.ToLower(currentDate.Format(\"January 02, 2006 15:04:05\")),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\ttempus := &Time{\n\t\t\tCurrentDate: currentDate,\n\t\t}\n\t\ttempus.Init(options.Map{}, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, tempus.Enabled())\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = tempus.Template()\n\t\t}\n\t\tif tc.ExpectedEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, tempus), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/todoist.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Todoist struct {\n\tBase\n\n\tTaskCount int\n}\n\ntype TasksResponse struct {\n\tResults []Task `json:\"results\"`\n}\n\ntype Task struct {\n\tID string `json:\"id\"`\n}\n\nfunc (t *Todoist) Enabled() bool {\n\terr := t.GetData()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\treturn true\n}\n\nfunc (t *Todoist) Template() string {\n\treturn \"{{ .TaskCount }} \"\n}\n\nfunc (t *Todoist) GetData() error {\n\tapikey := t.options.Template(APIKey, \".\", t)\n\n\thttpTimeout := t.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\taddHeaders := func(req *http.Request) {\n\t\treq.Header.Set(\"Authorization\", \"Bearer \"+apikey)\n\t\treq.Header.Set(\"Accept\", \"application/json\")\n\t}\n\n\tbody, err := t.env.HTTPRequest(\"https://api.todoist.com/api/v1/tasks/filter?query=due today\", nil, httpTimeout, addHeaders)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar response TasksResponse\n\tif err := json.Unmarshal(body, &response); err != nil {\n\t\treturn err\n\t}\n\n\tt.TaskCount = len(response.Results)\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/todoist_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst TodoistTestURL = \"https://api.todoist.com/api/v1/tasks/filter?query=due today\"\n\nfunc TestTodoistSegment(t *testing.T) {\n\tcases := []struct {\n\t\tError           error\n\t\tCase            string\n\t\tJSONResponse    string\n\t\tExpectedCount   int\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"No tasks\",\n\t\t\tJSONResponse:    `{\"results\": []}`,\n\t\t\tExpectedCount:   0,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Single task\",\n\t\t\tJSONResponse:    `{\"results\": [{\"id\": \"123\"}]}`,\n\t\t\tExpectedCount:   1,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Multiple tasks\",\n\t\t\tJSONResponse:    `{\"results\": [{\"id\": \"1\"}, {\"id\": \"2\"}, {\"id\": \"3\"}]}`,\n\t\t\tExpectedCount:   3,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"API error\",\n\t\t\tJSONResponse:    ``,\n\t\t\tExpectedCount:   0,\n\t\t\tExpectedEnabled: false,\n\t\t\tError:           errors.New(\"API request failed\"),\n\t\t},\n\t\t{\n\t\t\tCase:            \"Invalid JSON response\",\n\t\t\tJSONResponse:    `invalid json`,\n\t\t\tExpectedCount:   0,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Task with additional fields\",\n\t\t\tJSONResponse:    `{\"results\": [{\"id\": \"456\", \"content\": \"Buy milk\", \"due\": {\"date\": \"2024-01-15\"}}]}`,\n\t\t\tExpectedCount:   1,\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tenv := new(mock.Environment)\n\t\t\tprops := options.Map{\n\t\t\t\tAPIKey: \"fake-api-key\",\n\t\t\t}\n\n\t\t\tenv.On(\"HTTPRequest\", TodoistTestURL).Return([]byte(tc.JSONResponse), tc.Error)\n\n\t\t\ttodoist := &Todoist{}\n\t\t\ttodoist.Init(props, env)\n\n\t\t\tenabled := todoist.Enabled()\n\t\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\t\tif enabled {\n\t\t\t\tassert.Equal(t, tc.ExpectedCount, todoist.TaskCount, tc.Case)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTodoistTemplate(t *testing.T) {\n\ttodoist := &Todoist{}\n\tassert.Equal(t, \"{{ .TaskCount }} \", todoist.Template())\n}\n\nfunc TestTodoistTemplateRendering(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tJSONResponse   string\n\t\tTemplate       string\n\t\tExpectedString string\n\t}{\n\t\t{\n\t\t\tCase:           \"Default template with no tasks\",\n\t\t\tJSONResponse:   `{\"results\": []}`,\n\t\t\tTemplate:       \"{{ .TaskCount }}\",\n\t\t\tExpectedString: \"0\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Default template with tasks\",\n\t\t\tJSONResponse:   `{\"results\": [{\"id\": \"1\"}, {\"id\": \"2\"}]}`,\n\t\t\tTemplate:       \"{{ .TaskCount }}\",\n\t\t\tExpectedString: \"2\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Custom template with icon\",\n\t\t\tJSONResponse:   `{\"results\": [{\"id\": \"1\"}, {\"id\": \"2\"}, {\"id\": \"3\"}]}`,\n\t\t\tTemplate:       \"📋 {{ .TaskCount }} tasks\",\n\t\t\tExpectedString: \"📋 3 tasks\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Conditional template - has tasks\",\n\t\t\tJSONResponse:   `{\"results\": [{\"id\": \"1\"}]}`,\n\t\t\tTemplate:       \"{{ if gt .TaskCount 0 }}📋 {{ .TaskCount }}{{ end }}\",\n\t\t\tExpectedString: \"📋 1\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"Conditional template - no tasks\",\n\t\t\tJSONResponse:   `{\"results\": []}`,\n\t\t\tTemplate:       \"{{ if gt .TaskCount 0 }}📋 {{ .TaskCount }}{{ else }}✅{{ end }}\",\n\t\t\tExpectedString: \"✅\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tenv := new(mock.Environment)\n\t\t\tprops := options.Map{\n\t\t\t\tAPIKey: \"fake-api-key\",\n\t\t\t}\n\n\t\t\tenv.On(\"HTTPRequest\", TodoistTestURL).Return([]byte(tc.JSONResponse), nil)\n\n\t\t\ttodoist := &Todoist{}\n\t\t\ttodoist.Init(props, env)\n\n\t\t\tenabled := todoist.Enabled()\n\t\t\tassert.True(t, enabled, tc.Case)\n\n\t\t\tresult := renderTemplate(env, tc.Template, todoist)\n\t\t\tassert.Equal(t, tc.ExpectedString, result, tc.Case)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/segments/ui5tooling.go",
    "content": "package segments\n\nconst UI5ToolingYamlPattern = \"*ui5*.y*ml\"\n\ntype UI5Tooling struct {\n\tLanguage\n\tHasUI5YamlInParentDir bool\n}\n\nfunc (u *UI5Tooling) Template() string {\n\treturn languageTemplate\n}\n\nfunc (u *UI5Tooling) Enabled() bool {\n\tu.extensions = []string{UI5ToolingYamlPattern}\n\tu.displayMode = u.options.String(DisplayMode, DisplayModeContext)\n\tu.tooling = map[string]*cmd{\n\t\t\"ui5\": {\n\t\t\texecutable: \"ui5\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?:(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+))))`,\n\t\t},\n\t}\n\tu.defaultTooling = []string{\"ui5\"}\n\tu.versionURLTemplate = \"https://github.com/SAP/ui5-cli/releases/tag/v{{ .Full }}\"\n\tu.Language.loadContext = u.loadContext\n\tu.Language.inContext = u.inContext\n\n\treturn u.Language.Enabled()\n}\n\nfunc (u *UI5Tooling) loadContext() {\n\t// for searching ui5 yaml from subdirectories of UI5 project root - up to 4 levels\n\tu.HasUI5YamlInParentDir = u.env.HasFileInParentDirs(UI5ToolingYamlPattern, 4)\n}\n\nfunc (u *UI5Tooling) inContext() bool {\n\treturn u.HasUI5YamlInParentDir\n}\n"
  },
  {
    "path": "src/segments/ui5tooling_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/template\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nconst (\n\tWorkingDirRoot = \"/home/user/dev/my-app\"\n)\n\ntype testCase struct {\n\tCase            string\n\tTemplate        string\n\tExpectedString  string\n\tUI5YamlFilename string\n\tWorkingDir      string\n\tVersion         string\n\tDisplayMode     string\n}\n\nfunc TestUI5Tooling(t *testing.T) {\n\tcases := []testCase{\n\t\t{\n\t\t\tCase:            \"1) ui5tooling 2.12.1 - file ui5.yaml present in cwd; DisplayMode = files\",\n\t\t\tExpectedString:  \"2.12.1\",\n\t\t\tUI5YamlFilename: \"ui5.yaml\",\n\t\t\tVersion:         `2.12.1 (from C:\\somewhere\\cli\\bin\\ui5.js)`,\n\t\t\tDisplayMode:     DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:            \"2) ui5tooling 2.12.2 - file ui5.yaml present in cwd; default display mode (context)\",\n\t\t\tExpectedString:  \"2.12.2\",\n\t\t\tUI5YamlFilename: \"ui5.yaml\",\n\t\t\tVersion:         `2.12.2 (from C:\\somewhere\\cli\\bin\\ui5.js)`,\n\t\t},\n\t\t{\n\t\t\tCase:            \"3) ui5tooling 2.12.3 - file ui5.yaml present; cwd is sub dir, default display mode (context)\",\n\t\t\tExpectedString:  \"2.12.3\",\n\t\t\tWorkingDir:      WorkingDirRoot + \"/subdir\",\n\t\t\tUI5YamlFilename: \"ui5.yaml\",\n\t\t\tVersion:         `2.12.3 (from C:\\somewhere\\cli\\bin\\ui5.js)`,\n\t\t},\n\t\t{\n\t\t\tCase:            \"5) ui5tooling 2.12.4 - file ui5-dist.yml present in cwd\",\n\t\t\tExpectedString:  \"2.12.4\",\n\t\t\tUI5YamlFilename: \"ui5-dist.yml\",\n\t\t\tVersion:         `2.12.4 (from C:\\somewhere\\cli\\bin\\ui5.js)`,\n\t\t\tDisplayMode:     DisplayModeFiles,\n\t\t},\n\t\t{\n\t\t\tCase:           \"8) ui5tooling 11.0.0-rc1, no ui5.yaml file but display mode = always\",\n\t\t\tTemplate:       \"{{ .Major }}\",\n\t\t\tExpectedString: \"11\",\n\t\t\tVersion:        `11.0.0-rc1 (from C:\\somewhere\\cli\\bin\\ui5.js)`,\n\t\t\tDisplayMode:    DisplayModeAlways,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"ui5\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     UI5ToolingYamlPattern,\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tif tc.DisplayMode == \"\" {\n\t\t\ttc.DisplayMode = DisplayModeContext\n\t\t}\n\n\t\tprops[DisplayMode] = tc.DisplayMode\n\n\t\tui5tooling := &UI5Tooling{}\n\t\tui5tooling.Init(props, env)\n\n\t\terr := mockFilePresence(&tc, env)\n\n\t\tif err != nil {\n\t\t\tt.Fail()\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = ui5tooling.Template()\n\t\t}\n\n\t\t// this is needed to build the version URL as before renderTemplate, the template is not initialized\n\t\tenv.On(\"Shell\").Return(\"foo\")\n\t\ttemplate.Cache = &cache.Template{}\n\t\ttemplate.Init(env, nil, nil)\n\n\t\tfailMsg := fmt.Sprintf(\"Failed in case: %s\", tc.Case)\n\t\tassert.True(t, ui5tooling.Enabled(), failMsg)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, ui5tooling), failMsg)\n\t}\n}\n\nfunc mockFilePresence(tc *testCase, env *mock.Environment) error {\n\tfor _, f := range []string{UI5ToolingYamlPattern} {\n\t\tmatch, err := filepath.Match(f, tc.UI5YamlFilename)\n\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tif match {\n\t\t\tif tc.DisplayMode == DisplayModeFiles && tc.WorkingDir == WorkingDirRoot { //nolint: gocritic\n\t\t\t\tenv.On(\"HasFiles\", f).Return(true)\n\t\t\t\tenv.On(\"HasFileInParentDirs\", f, uint(4)).Return(false)\n\t\t\t\t// mode context, working dir != working dir root\n\t\t\t} else if tc.DisplayMode == DisplayModeContext {\n\t\t\t\tenv.On(\"HasFileInParentDirs\", f, uint(4)).Return(false)\n\t\t\t\tenv.On(\"HasFiles\", f).Return(true)\n\t\t\t} else {\n\t\t\t\tenv.On(\"HasFileInParentDirs\", f, uint(4)).Return(false)\n\t\t\t\tenv.On(\"HasFiles\", f).Return(false)\n\t\t\t}\n\t\t} else {\n\t\t\tenv.On(\"HasFileInParentDirs\", f, uint(4)).Return(false)\n\t\t\tenv.On(\"HasFiles\", f).Return(false)\n\t\t}\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/umbraco.go",
    "content": "package segments\n\nimport (\n\t\"encoding/xml\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Umbraco struct {\n\tBase\n\n\tVersion string\n\tModern  bool\n}\n\ntype CSProj struct {\n\tPackageReferences []struct {\n\t\tName    string `xml:\"include,attr\"`\n\t\tVersion string `xml:\"version,attr\"`\n\t} `xml:\"ItemGroup>PackageReference\"`\n}\n\ntype WebConfig struct {\n\tAppSettings []struct {\n\t\tKey   string `xml:\"key,attr\"`\n\t\tValue string `xml:\"value,attr\"`\n\t} `xml:\"appSettings>add\"`\n}\n\nfunc (u *Umbraco) Enabled() bool {\n\tvar location string\n\n\t// Check if we have a folder called Umbraco or umbraco in the current directory or a parent directory\n\tfolders := []string{\"umbraco\", \"Umbraco\"}\n\tfor _, folder := range folders {\n\t\tif file, err := u.env.HasParentFilePath(folder, false); err == nil {\n\t\t\tlocation = file.ParentFolder\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif location == \"\" {\n\t\tlog.Debug(\"no umbraco folder found in parent directories\")\n\t\treturn false\n\t}\n\n\tfiles := u.env.LsDir(location)\n\n\t// Loop over files where we found the Umbraco folder\n\t// To see if we can find a web.config or *.csproj file\n\t// If we do then we can scan the file to see if Umbraco has been installed\n\tfor _, file := range files {\n\t\tif file.IsDir() {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.EqualFold(file.Name(), \"web.config\") {\n\t\t\tif u.TryFindLegacyUmbraco(filepath.Join(location, file.Name())) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// We may have found a web.config first before a *.csproj file\n\t\t\t// So we need to keep checking to see if modern Umbraco is installed if we come across a *.csproj file\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.EqualFold(filepath.Ext(file.Name()), \".csproj\") {\n\t\t\tif u.TryFindModernUmbraco(filepath.Join(location, file.Name())) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// We may have found a *.csproj first before a web.config file\n\t\t\t// So we need to keep checking if legacy Umbraco is installed (as the *.csproj could be for a non-Umbraco project)\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (u *Umbraco) Template() string {\n\treturn \"{{.Version}} \"\n}\n\nfunc (u *Umbraco) TryFindModernUmbraco(configPath string) bool {\n\t// Check the passed in filepath is not empty\n\tif configPath == \"\" {\n\t\tlog.Debug(\"no configPath provided\")\n\t\treturn false\n\t}\n\n\t// Read the file contents of the csproj file\n\tcontents := u.env.FileContent(configPath)\n\n\t// As XML unmarshal does not support case insenstivity attributes\n\t// this is just a simple string replace to lowercase the attribute\n\tcontents = strings.ReplaceAll(contents, \"Include=\", \"include=\")\n\tcontents = strings.ReplaceAll(contents, \"Version=\", \"version=\")\n\n\t// XML Unmarshal - map the contents of the file to the CSProj struct\n\tcsProjPackages := CSProj{}\n\terr := xml.Unmarshal([]byte(contents), &csProjPackages)\n\n\tif err != nil {\n\t\tlog.Debug(err.Error())\n\t}\n\n\t// Loop over all the package references\n\tfor _, packageReference := range csProjPackages.PackageReferences {\n\t\tif strings.EqualFold(packageReference.Name, \"umbraco.cms\") {\n\t\t\tu.Modern = true\n\t\t\tu.Version = packageReference.Version\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc (u *Umbraco) TryFindLegacyUmbraco(configPath string) bool {\n\t// Check the passed in filepath is not empty\n\tif configPath == \"\" {\n\t\tlog.Debug(\"no configPath provided\")\n\t\treturn false\n\t}\n\n\t// Read the file contents of the web.config\n\tcontents := u.env.FileContent(configPath)\n\n\t// As XML unmarshal does not support case insenstivity attributes\n\t// this is just a simple string replace to lowercase the attribute\n\tcontents = strings.ReplaceAll(contents, \"Key=\", \"key=\")\n\tcontents = strings.ReplaceAll(contents, \"Value=\", \"value=\")\n\n\t// XML Unmarshal - web.config all AppSettings keys\n\twebConfigAppSettings := WebConfig{}\n\terr := xml.Unmarshal([]byte(contents), &webConfigAppSettings)\n\n\tif err != nil {\n\t\tlog.Debug(err.Error())\n\t}\n\n\t// Loop over all the package references\n\tfor _, appSetting := range webConfigAppSettings.AppSettings {\n\t\tif strings.EqualFold(appSetting.Key, \"umbraco.core.configurationstatus\") || strings.EqualFold(appSetting.Key, \"umbracoConfigurationStatus\") {\n\t\t\tu.Modern = false\n\t\t\tu.Version = appSetting.Value\n\n\t\t\tif u.Version == \"\" {\n\t\t\t\tu.Version = UNKNOWN\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/umbraco_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestUmbracoSegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase                    string\n\t\tExpectedString          string\n\t\tTemplate                string\n\t\tExpectedEnabled         bool\n\t\tHasUmbracoFolder        bool\n\t\tHasCsproj               bool\n\t\tHasWebConfig            bool\n\t\tUseLegacyWebConfig      bool\n\t\tHasCSProjWithoutUmbraco bool\n\t}{\n\t\t{\n\t\t\tCase:             \"No Umbraco folder found\",\n\t\t\tHasUmbracoFolder: false,\n\t\t\tExpectedEnabled:  false, // Segment should not be enabled\n\t\t},\n\t\t{\n\t\t\tCase:             \"Umbraco Folder but NO web.config or .csproj\",\n\t\t\tHasUmbracoFolder: true,\n\t\t\tHasCsproj:        false,\n\t\t\tHasWebConfig:     false,\n\t\t\tExpectedEnabled:  false, // Segment should not be enabled\n\t\t},\n\t\t{\n\t\t\tCase:             \"Umbraco Folder and web.config but NO .csproj\",\n\t\t\tHasUmbracoFolder: true,\n\t\t\tHasCsproj:        false,\n\t\t\tHasWebConfig:     true,\n\t\t\tExpectedEnabled:  true, // Segment should be enabled and visible\n\t\t\tTemplate:         \"{{ .Version }}\",\n\t\t\tExpectedString:   \"8.18.9\",\n\t\t},\n\t\t{\n\t\t\tCase:               \"Umbraco Folder and web.config but NO .csproj and uses older web.config\",\n\t\t\tHasUmbracoFolder:   true,\n\t\t\tHasCsproj:          false,\n\t\t\tHasWebConfig:       true,\n\t\t\tUseLegacyWebConfig: true,\n\t\t\tExpectedEnabled:    true, // Segment should be enabled and visible\n\t\t\tTemplate:           \"{{ .Version }}\",\n\t\t\tExpectedString:     \"4.11.10\",\n\t\t},\n\t\t{\n\t\t\tCase:             \"Umbraco Folder and .csproj but NO web.config\",\n\t\t\tHasUmbracoFolder: true,\n\t\t\tHasCsproj:        true,\n\t\t\tHasWebConfig:     false,\n\t\t\tExpectedEnabled:  true, // Segment should be enabled and visible\n\t\t\tTemplate:         \"{{ .Version }}\",\n\t\t\tExpectedString:   \"12.1.2\",\n\t\t},\n\t\t{\n\t\t\tCase:                    \"Umbraco Folder with a .csproj [without Umbraco] and a web.config\",\n\t\t\tHasUmbracoFolder:        true,\n\t\t\tHasCsproj:               false,\n\t\t\tHasWebConfig:            true,\n\t\t\tHasCSProjWithoutUmbraco: true, // This is a .csproj file without Umbraco installed - so we can test it doesn't return but carries on checking for more csproj or web.config files\n\t\t\tExpectedEnabled:         true, // Segment should not be visible\n\t\t\tTemplate:                \"{{ .Version }}\",\n\t\t\tExpectedString:          \"8.18.9\",\n\t\t},\n\t\t{\n\t\t\tCase:                    \"Umbraco Folder with a .csproj [without Umbraco] and NO web.config\",\n\t\t\tHasUmbracoFolder:        true,\n\t\t\tHasCsproj:               false,\n\t\t\tHasWebConfig:            false,\n\t\t\tHasCSProjWithoutUmbraco: true,\n\t\t\tExpectedEnabled:         false,\n\t\t\tTemplate:                \"{{ .Version }}\",\n\t\t\tExpectedString:          \"\",\n\t\t},\n\t\t{\n\t\t\tCase:                    \"Umbraco Folder with multiple .csproj's and NO web.config\",\n\t\t\tHasUmbracoFolder:        true,\n\t\t\tHasCsproj:               true,\n\t\t\tHasWebConfig:            false,\n\t\t\tHasCSProjWithoutUmbraco: true,\n\t\t\tExpectedEnabled:         true, // Segment should be enabled and visible\n\t\t\tTemplate:                \"{{ .Version }}\",\n\t\t\tExpectedString:          \"12.1.2\",\n\t\t},\n\t\t{\n\t\t\tCase:             \"Umbraco Folder and .csproj with custom template\",\n\t\t\tHasUmbracoFolder: true,\n\t\t\tHasCsproj:        true,\n\t\t\tExpectedEnabled:  true,\n\t\t\tTemplate:         \"Version:{{ .Version }} ModernUmbraco:{{ .Modern }}\",\n\t\t\tExpectedString:   \"Version:12.1.2 ModernUmbraco:true\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\t// Prepare/arrange the test\n\t\tenv := new(mock.Environment)\n\t\tvar sampleCSProj, sampleWebConfig, sampleNonUmbracoCSProj string\n\n\t\tif tc.HasCsproj {\n\t\t\tcontent, _ := os.ReadFile(\"../test/umbraco/MyProject.csproj\")\n\t\t\tsampleCSProj = string(content)\n\t\t}\n\t\tif tc.HasWebConfig {\n\t\t\tvar filePath string\n\t\t\tif tc.UseLegacyWebConfig {\n\t\t\t\tfilePath = \"../test/umbraco/web.old.config\"\n\t\t\t} else {\n\t\t\t\tfilePath = \"../test/umbraco/web.config\"\n\t\t\t}\n\n\t\t\tcontent, _ := os.ReadFile(filePath)\n\t\t\tsampleWebConfig = string(content)\n\t\t}\n\t\tif tc.HasCSProjWithoutUmbraco {\n\t\t\tcontent, _ := os.ReadFile(\"../test/umbraco/ANonUmbracoProject.csproj\")\n\t\t\tsampleNonUmbracoCSProj = string(content)\n\t\t}\n\n\t\tconst umbracoProjectDirectory = \"/workspace/MyProject\"\n\t\tenv.On(\"Pwd\").Return(umbracoProjectDirectory)\n\t\tenv.On(\"FileContent\", filepath.Join(umbracoProjectDirectory, \"MyProject.csproj\")).Return(sampleCSProj)\n\t\tenv.On(\"FileContent\", filepath.Join(umbracoProjectDirectory, \"ANonUmbracoProject.csproj\")).Return(sampleNonUmbracoCSProj)\n\t\tenv.On(\"FileContent\", filepath.Join(umbracoProjectDirectory, \"web.config\")).Return(sampleWebConfig)\n\n\t\tif tc.HasUmbracoFolder {\n\t\t\tfileInfo := &runtime.FileInfo{\n\t\t\t\tPath:         \"/workspace/MyProject/Umbraco\",\n\t\t\t\tParentFolder: \"/workspace/MyProject\",\n\t\t\t\tIsDir:        true,\n\t\t\t}\n\n\t\t\tenv.On(\"HasParentFilePath\", \"umbraco\", false).Return(fileInfo, nil)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \"Umbraco\", false).Return(&runtime.FileInfo{}, errors.New(\"no such file or directory\"))\n\t\t\tenv.On(\"HasParentFilePath\", \"umbraco\", false).Return(&runtime.FileInfo{}, errors.New(\"no such file or directory\"))\n\t\t}\n\n\t\tdirEntries := []fs.DirEntry{}\n\t\tif tc.HasCsproj {\n\t\t\tdirEntries = append(dirEntries, &MockDirEntry{\n\t\t\t\tname:  \"MyProject.csproj\",\n\t\t\t\tisDir: false,\n\t\t\t})\n\t\t}\n\n\t\tif tc.HasWebConfig {\n\t\t\tdirEntries = append(dirEntries, &MockDirEntry{\n\t\t\t\tname:  \"web.config\",\n\t\t\t\tisDir: false,\n\t\t\t})\n\t\t}\n\n\t\tif tc.HasCSProjWithoutUmbraco {\n\t\t\tdirEntries = append(dirEntries, &MockDirEntry{\n\t\t\t\tname:  \"ANonUmbracoProject.csproj\",\n\t\t\t\tisDir: false,\n\t\t\t})\n\t\t}\n\n\t\tenv.On(\"LsDir\", umbracoProjectDirectory).Return(dirEntries)\n\n\t\t// Setup the Umbraco segment with the mocked environment & properties\n\t\tumb := &Umbraco{}\n\t\tumb.Init(options.Map{}, env)\n\n\t\t// Assert the test results\n\t\t// Check if the segment should be enabled and\n\t\t// the rendered string matches what we expect when specifying a template for the segment\n\t\tassert.Equal(t, tc.ExpectedEnabled, umb.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, tc.Template, umb), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/unity.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Unity struct {\n\tBase\n\n\tUnityVersion  string\n\tCSharpVersion string\n}\n\nfunc (u *Unity) Template() string {\n\treturn \" \\ue721 {{ .UnityVersion }}{{ if .CSharpVersion }} {{ .CSharpVersion }}{{ end }} \"\n}\n\nfunc (u *Unity) Enabled() bool {\n\tunityVersion, err := u.GetUnityVersion()\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn false\n\t}\n\tif unityVersion == \"\" {\n\t\treturn false\n\t}\n\tu.UnityVersion = unityVersion\n\n\tcsharpVersion, err := u.GetCSharpVersion()\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\tu.CSharpVersion = csharpVersion\n\n\treturn true\n}\n\nfunc (u *Unity) GetUnityVersion() (string, error) {\n\tprojectDir, err := u.env.HasParentFilePath(\"ProjectSettings\", false)\n\tif err != nil {\n\t\tlog.Debug(\"no ProjectSettings parent folder found\")\n\t\treturn \"\", err\n\t}\n\n\tif !u.env.HasFilesInDir(projectDir.Path, \"ProjectVersion.txt\") {\n\t\tlog.Debug(\"no ProjectVersion.txt file found\")\n\t\treturn \"\", err\n\t}\n\n\tversionFilePath := filepath.Join(projectDir.Path, \"ProjectVersion.txt\")\n\tversionFileText := u.env.FileContent(versionFilePath)\n\n\tlines := strings.SplitSeq(versionFileText, \"\\n\")\n\tversionPrefix := \"m_EditorVersion: \"\n\tfor line := range lines {\n\t\tif !strings.HasPrefix(line, versionPrefix) {\n\t\t\tcontinue\n\t\t}\n\t\tversion := strings.TrimPrefix(line, versionPrefix)\n\t\tversion = strings.TrimSpace(version)\n\t\tif version == \"\" {\n\t\t\treturn \"\", errors.New(\"empty m_EditorVersion\")\n\t\t}\n\t\tfIndex := strings.Index(version, \"f\")\n\t\tif fIndex > 0 {\n\t\t\treturn version[:fIndex], nil\n\t\t}\n\t\treturn version, nil\n\t}\n\n\treturn \"\", errors.New(\"ProjectSettings/ProjectVersion.txt is missing m_EditorVersion\")\n}\n\nfunc (u *Unity) GetCSharpVersion() (version string, err error) {\n\tlastDotIndex := strings.LastIndex(u.UnityVersion, \".\")\n\tif lastDotIndex == -1 {\n\t\treturn \"\", errors.New(\"lastDotIndex\")\n\t}\n\tshortUnityVersion := u.UnityVersion[0:lastDotIndex]\n\n\tvar csharpVersionsByUnityVersion = map[string]string{\n\t\t\"2017.1\": \"C# 6\",\n\t\t\"2017.2\": \"C# 6\",\n\t\t\"2017.3\": \"C# 6\",\n\t\t\"2017.4\": \"C# 6\",\n\t\t\"2018.1\": \"C# 6\",\n\t\t\"2018.2\": \"C# 6\",\n\t\t\"2018.3\": \"C# 7.3\",\n\t\t\"2018.4\": \"C# 7.3\",\n\t\t\"2019.1\": \"C# 7.3\",\n\t\t\"2019.2\": \"C# 7.3\",\n\t\t\"2019.3\": \"C# 7.3\",\n\t\t\"2019.4\": \"C# 7.3\",\n\t\t\"2020.1\": \"C# 7.3\",\n\t\t\"2020.2\": \"C# 8\",\n\t\t\"2020.3\": \"C# 8\",\n\t\t\"2021.1\": \"C# 8\",\n\t\t\"2021.2\": \"C# 9\",\n\t\t\"2021.3\": \"C# 9\",\n\t\t\"2022.1\": \"C# 9\",\n\t\t\"2022.2\": \"C# 9\",\n\t\t\"2023.1\": \"C# 9\",\n\t\t\"2023.2\": \"C# 9\",\n\t}\n\n\tcsharpVersion, found := csharpVersionsByUnityVersion[shortUnityVersion]\n\tif found {\n\t\treturn csharpVersion, nil\n\t}\n\n\tlog.Debug(fmt.Sprintf(\"Unity version %s doesn't exist in the map\", shortUnityVersion))\n\treturn u.GetCSharpVersionFromWeb(shortUnityVersion)\n}\n\nfunc (u *Unity) GetCSharpVersionFromWeb(shortUnityVersion string) (version string, err error) {\n\turl := fmt.Sprintf(\"https://docs.unity3d.com/%s/Documentation/Manual/CSharpCompiler.html\", shortUnityVersion)\n\thttpTimeout := u.options.Int(options.HTTPTimeout, 2000)\n\n\tbody, err := u.env.HTTPRequest(url, nil, httpTimeout)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tpageContent := string(body)\n\n\tpattern := `<a href=\"https://(?:docs|learn)\\.microsoft\\.com/en-us/dotnet/csharp/whats-new/csharp-[0-9]+-?[0-9]*\">(?P<csharpVersion>.*)</a>`\n\tmatches := regex.FindNamedRegexMatch(pattern, pageContent)\n\tif matches != nil && matches[\"csharpVersion\"] != \"\" {\n\t\tcsharpVersion := strings.TrimSuffix(matches[\"csharpVersion\"], \".0\")\n\t\treturn csharpVersion, nil\n\t}\n\n\treturn \"\", nil\n}\n"
  },
  {
    "path": "src/segments/unity_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\ntype HTTPResponse struct {\n\terr  error\n\tbody string\n}\n\nfunc TestUnitySegment(t *testing.T) {\n\tcases := []struct {\n\t\tCase                string\n\t\tExpectedOutput      string\n\t\tVersionFileText     string\n\t\tExpectedToBeEnabled bool\n\t\tVersionFileExists   bool\n\t}{\n\t\t{\n\t\t\tCase:                \"Unity version without f suffix\",\n\t\t\tExpectedOutput:      \"\\ue721 2023.2.0a9 C# 9\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2023.2.0a9\\nm_EditorVersionWithRevision: 2023.2.0a9 (5405d0db74a0)\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"Unity version exists in C# map\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.3.16 C# 9\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.3.16f1\\nm_EditorVersionWithRevision: 2021.3.16f1 (4016570cf34f)\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"ProjectSettings/ProjectVersion.txt doesn't exist\",\n\t\t\tExpectedToBeEnabled: false,\n\t\t\tVersionFileExists:   false,\n\t\t},\n\t\t{\n\t\t\tCase:                \"ProjectSettings/ProjectVersion.txt is empty\",\n\t\t\tExpectedToBeEnabled: false,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"ProjectSettings/ProjectVersion.txt does not have expected format\",\n\t\t\tExpectedToBeEnabled: false,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"2021.3.16f1\",\n\t\t},\n\t\t{\n\t\t\tCase:                \"CRLF line ending\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.3.16 C# 9\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.3.16f1\\r\\nm_EditorVersionWithRevision: 2021.3.16f1 (4016570cf34f)\\r\\n\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\terr := errors.New(\"no match at root level\")\n\t\tvar projectDir *runtime.FileInfo\n\t\tif tc.VersionFileExists {\n\t\t\terr = nil\n\t\t\tprojectDir = &runtime.FileInfo{\n\t\t\t\tParentFolder: \"UnityProjectRoot\",\n\t\t\t\tPath:         \"UnityProjectRoot/ProjectSettings\",\n\t\t\t\tIsDir:        true,\n\t\t\t}\n\t\t\tenv.On(\"HasFilesInDir\", projectDir.Path, \"ProjectVersion.txt\").Return(tc.VersionFileExists)\n\t\t\tversionFilePath := filepath.Join(projectDir.Path, \"ProjectVersion.txt\")\n\t\t\tenv.On(\"FileContent\", versionFilePath).Return(tc.VersionFileText)\n\t\t}\n\t\tenv.On(\"HasParentFilePath\", \"ProjectSettings\", false).Return(projectDir, err)\n\n\t\tprops := options.Map{}\n\t\tunity := &Unity{}\n\t\tunity.Init(props, env)\n\t\tassert.Equal(t, tc.ExpectedToBeEnabled, unity.Enabled())\n\t\tif tc.ExpectedToBeEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedOutput, renderTemplate(env, unity.Template(), unity), tc.Case)\n\t\t}\n\t}\n}\n\n// 2021.9.20f1 is used in the test cases below as a fake Unity version.\n// As such, it doesn't exist in the predefined map in unity.go. This\n// allows us to test the web request portion of the code, which is the\n// fallback for obtaining a C# version.\nfunc TestUnitySegmentCSharpWebRequest(t *testing.T) {\n\tcases := []struct {\n\t\tHTTPResponse        HTTPResponse\n\t\tCase                string\n\t\tExpectedOutput      string\n\t\tVersionFileText     string\n\t\tExpectedToBeEnabled bool\n\t\tVersionFileExists   bool\n\t}{\n\t\t{\n\t\t\tCase:                \"C# version\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.9.20 C# 10\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.9.20f1\\nm_EditorVersionWithRevision: 2021.9.20f1 (4016570cf34f)\",\n\t\t\tHTTPResponse: HTTPResponse{\n\t\t\t\tbody: `<a href=\"https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10\">C# 10.0</a>`,\n\t\t\t\terr:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:                \"C# version has a minor version\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.9.20 C# 10.1\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.9.20f1\\nm_EditorVersionWithRevision: 2021.9.20f1 (4016570cf34f)\",\n\t\t\tHTTPResponse: HTTPResponse{\n\t\t\t\tbody: `<a href=\"https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10-1\">C# 10.1</a>`,\n\t\t\t\terr:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:                \"C# version not found in webpage\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.9.20\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.9.20f1\\nm_EditorVersionWithRevision: 2021.9.20f1 (4016570cf34f)\",\n\t\t\tHTTPResponse: HTTPResponse{\n\t\t\t\tbody: `<h1>Sorry... that page seems to be missing!</h1>`,\n\t\t\t\terr:  nil,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:                \"http request fails\",\n\t\t\tExpectedOutput:      \"\\ue721 2021.9.20\",\n\t\t\tExpectedToBeEnabled: true,\n\t\t\tVersionFileExists:   true,\n\t\t\tVersionFileText:     \"m_EditorVersion: 2021.9.20f1\\nm_EditorVersionWithRevision: 2021.9.20f1 (4016570cf34f)\",\n\t\t\tHTTPResponse: HTTPResponse{\n\t\t\t\tbody: \"\",\n\t\t\t\terr:  errors.New(\"FAIL\"),\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\terr := errors.New(\"no match at root level\")\n\t\tvar projectDir *runtime.FileInfo\n\t\tif tc.VersionFileExists {\n\t\t\terr = nil\n\t\t\tprojectDir = &runtime.FileInfo{\n\t\t\t\tParentFolder: \"UnityProjectRoot\",\n\t\t\t\tPath:         \"UnityProjectRoot/ProjectSettings\",\n\t\t\t\tIsDir:        true,\n\t\t\t}\n\t\t\tenv.On(\"HasFilesInDir\", projectDir.Path, \"ProjectVersion.txt\").Return(tc.VersionFileExists)\n\t\t\tversionFilePath := filepath.Join(projectDir.Path, \"ProjectVersion.txt\")\n\t\t\tenv.On(\"FileContent\", versionFilePath).Return(tc.VersionFileText)\n\t\t}\n\t\tenv.On(\"HasParentFilePath\", \"ProjectSettings\", false).Return(projectDir, err)\n\n\t\turl := \"https://docs.unity3d.com/2021.9/Documentation/Manual/CSharpCompiler.html\"\n\t\tenv.On(\"HTTPRequest\", url).Return([]byte(tc.HTTPResponse.body), tc.HTTPResponse.err)\n\n\t\tprops := options.Map{}\n\t\tunity := &Unity{}\n\t\tunity.Init(props, env)\n\t\tassert.Equal(t, tc.ExpectedToBeEnabled, unity.Enabled())\n\t\tif tc.ExpectedToBeEnabled {\n\t\t\tassert.Equal(t, tc.ExpectedOutput, renderTemplate(env, unity.Template(), unity), tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/upgrade.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype UpgradeCache struct {\n\tLatest  string `json:\"latest\"`\n\tCurrent string `json:\"current\"`\n}\n\ntype Upgrade struct {\n\tBase\n\n\t// deprecated\n\tVersion string\n\n\tUpgradeCache\n}\n\nconst (\n\tUPGRADECACHEKEY = \"upgrade_segment\"\n)\n\nfunc (u *Upgrade) Template() string {\n\treturn \" \\uf019 \"\n}\n\nfunc (u *Upgrade) Enabled() bool {\n\tu.Current = build.Version\n\tupgradeCache, err := u.upgradeCache()\n\tif err != nil || upgradeCache.Current != u.Current {\n\t\tupgradeCache, err = u.checkUpdate(u.Current)\n\t}\n\n\tif err != nil || u.Current == upgradeCache.Latest {\n\t\treturn false\n\t}\n\n\tu.UpgradeCache = *upgradeCache\n\tu.Version = u.Latest\n\treturn true\n}\n\nfunc (u *Upgrade) upgradeCache() (*UpgradeCache, error) {\n\tdata, ok := cache.Get[*UpgradeCache](cache.Device, UPGRADECACHEKEY)\n\tif !ok {\n\t\treturn nil, errors.New(\"no cache data\")\n\t}\n\n\treturn data, nil\n}\n\nfunc (u *Upgrade) checkUpdate(current string) (*UpgradeCache, error) {\n\tduration := u.options.String(options.CacheDuration, string(cache.ONEWEEK))\n\tsource := u.options.String(Source, string(upgrade.CDN))\n\n\tcfg := &upgrade.Config{\n\t\tSource:   upgrade.Source(source),\n\t\tInterval: cache.Duration(duration),\n\t}\n\n\tlatest, err := cfg.FetchLatest()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcacheData := &UpgradeCache{\n\t\tLatest:  latest,\n\t\tCurrent: current,\n\t}\n\n\tcache.Set(cache.Device, UPGRADECACHEKEY, cacheData, cache.Duration(duration))\n\n\treturn cacheData, nil\n}\n"
  },
  {
    "path": "src/segments/upgrade_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/upgrade\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestUpgrade(t *testing.T) {\n\tugc := &upgrade.Config{}\n\tlatest, _ := ugc.FetchLatest()\n\n\tcases := []struct {\n\t\tCase            string\n\t\tCurrentVersion  string\n\t\tLatestVersion   string\n\t\tCachedVersion   string\n\t\tExpectedEnabled bool\n\t\tHasCache        bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Should upgrade\",\n\t\t\tCurrentVersion:  \"1.0.0\",\n\t\t\tLatestVersion:   \"1.0.1\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"On latest\",\n\t\t\tCurrentVersion: latest,\n\t\t},\n\t\t{\n\t\t\tCase:            \"On previous, from cache\",\n\t\t\tHasCache:        true,\n\t\t\tCurrentVersion:  \"1.0.2\",\n\t\t\tLatestVersion:   latest,\n\t\t\tCachedVersion:   \"1.0.2\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"On latest, version changed\",\n\t\t\tHasCache:       true,\n\t\t\tCurrentVersion: latest,\n\t\t\tLatestVersion:  latest,\n\t\t\tCachedVersion:  \"1.0.1\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"On previous, version changed\",\n\t\t\tHasCache:        true,\n\t\t\tCurrentVersion:  \"1.0.2\",\n\t\t\tLatestVersion:   latest,\n\t\t\tCachedVersion:   \"1.0.1\",\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\n\t\tif tc.CachedVersion == \"\" {\n\t\t\ttc.CachedVersion = tc.CurrentVersion\n\t\t}\n\n\t\tif tc.HasCache {\n\t\t\tdata := &UpgradeCache{\n\t\t\t\tLatest:  tc.LatestVersion,\n\t\t\t\tCurrent: tc.CachedVersion,\n\t\t\t}\n\t\t\tcache.Set(cache.Device, UPGRADECACHEKEY, data, cache.INFINITE)\n\t\t}\n\n\t\tbuild.Version = tc.CurrentVersion\n\n\t\tug := &Upgrade{}\n\t\tug.Init(options.Map{}, env)\n\n\t\tenabled := ug.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\n\t\tcache.DeleteAll(cache.Device)\n\t}\n}\n"
  },
  {
    "path": "src/segments/v.go",
    "content": "package segments\n\ntype V struct {\n\tLanguage\n}\n\nfunc (v *V) Template() string {\n\treturn languageTemplate\n}\n\nfunc (v *V) Enabled() bool {\n\tv.extensions = []string{\"*.v\"}\n\n\tv.tooling = map[string]*cmd{\n\t\t\"v\": {\n\t\t\texecutable: \"v\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `V (?P<version>(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)) [a-f0-9]+`,\n\t\t},\n\t}\n\tv.defaultTooling = []string{\"v\"}\n\treturn v.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/v_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestV(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{\n\t\t\tCase:           \"V 0.4.9\",\n\t\t\tExpectedString: \"0.4.9\",\n\t\t\tVersion:        \"V 0.4.9 b487986\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"V 0.4.8\",\n\t\t\tExpectedString: \"0.4.8\",\n\t\t\tVersion:        \"V 0.4.8 a123456\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"V 0.4.7\",\n\t\t\tExpectedString: \"0.4.7\",\n\t\t\tVersion:        \"V 0.4.7 f789012\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"v\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.v\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tv := &V{}\n\t\tv.Init(props, env)\n\t\tassert.True(t, v.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, v.Template(), v), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/vala.go",
    "content": "package segments\n\ntype Vala struct {\n\tLanguage\n}\n\nfunc (v *Vala) Template() string {\n\treturn languageTemplate\n}\n\nfunc (v *Vala) Enabled() bool {\n\tv.extensions = []string{\"*.vala\"}\n\tv.tooling = map[string]*cmd{\n\t\t\"vala\": {\n\t\t\texecutable: \"vala\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `Vala (?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tv.defaultTooling = []string{\"vala\"}\n\tv.versionURLTemplate = \"https://gitlab.gnome.org/GNOME/vala/raw/{{ .Major }}.{{ .Minor }}/NEWS\"\n\n\treturn v.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/vala_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestVala(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{\n\t\t\tCase:           \"vala 0.48.17\",\n\t\t\tExpectedString: \"0.48.17\",\n\t\t\tVersion:        \"Vala 0.48.17\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"vala\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.vala\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tv := &Vala{}\n\t\tv.Init(props, env)\n\t\tassert.True(t, v.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, v.Template(), v), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/wakatime.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype Wakatime struct {\n\tBase\n\n\tWtData\n}\n\ntype wtTotals struct {\n\tText    string  `json:\"text\"`\n\tSeconds float64 `json:\"seconds\"`\n}\n\ntype WtData struct {\n\tStart           string   `json:\"start\"`\n\tEnd             string   `json:\"end\"`\n\tCumulativeTotal wtTotals `json:\"cumulative_total\"`\n}\n\nfunc (w *Wakatime) Template() string {\n\treturn \" {{ secondsRound .CumulativeTotal.Seconds }} \"\n}\n\nfunc (w *Wakatime) Enabled() bool {\n\terr := w.setAPIData()\n\treturn err == nil\n}\n\nfunc (w *Wakatime) setAPIData() error {\n\turl := w.options.Template(URL, \"\", w)\n\n\thttpTimeout := w.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout)\n\n\tbody, err := w.env.HTTPRequest(url, nil, httpTimeout)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = json.Unmarshal(body, &w.WtData)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "src/segments/wakatime_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWTTrackedTime(t *testing.T) {\n\tcases := []struct {\n\t\tError          error\n\t\tCase           string\n\t\tExpected       string\n\t\tTemplate       string\n\t\tSeconds        int\n\t\tCacheTimeout   int\n\t\tCacheFoundFail bool\n\t}{\n\t\t{\n\t\t\tCase:     \"nothing tracked\",\n\t\t\tSeconds:  0,\n\t\t\tExpected: \"0s\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"25 minutes\",\n\t\t\tSeconds:  1500,\n\t\t\tExpected: \"25m\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"2 hours\",\n\t\t\tSeconds:  7200,\n\t\t\tExpected: \"2h\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"2h 45m\",\n\t\t\tSeconds:  9900,\n\t\t\tExpected: \"2h 45m\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"negative number\",\n\t\t\tSeconds:  -9900,\n\t\t\tExpected: \"2h 45m\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"no cache 2h 45m\",\n\t\t\tSeconds:  9900,\n\t\t\tExpected: \"2h 45m\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"api error\",\n\t\t\tSeconds:  2,\n\t\t\tExpected: \"0s\",\n\t\t\tError:    errors.New(\"api error\"),\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tresponse := fmt.Sprintf(`{\"cumulative_total\": {\"seconds\": %.2f, \"text\": \"x\"}}`, float64(tc.Seconds))\n\n\t\tenv.On(\"HTTPRequest\", FAKEAPIURL).Return([]byte(response), tc.Error)\n\n\t\tprops := options.Map{\n\t\t\tURL: FAKEAPIURL,\n\t\t}\n\n\t\tw := &Wakatime{}\n\t\tw.Init(props, env)\n\n\t\tassert.ErrorIs(t, tc.Error, w.setAPIData(), tc.Case+\" - Error\")\n\t\tassert.Equal(t, tc.Expected, renderTemplate(env, w.Template(), w), tc.Case+\" - String\")\n\t}\n}\n"
  },
  {
    "path": "src/segments/winget.go",
    "content": "package segments\n\nimport (\n\t\"strings\"\n\t\"unicode\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\ntype WinGet struct {\n\tBase\n\n\tUpdates     []WinGetPackage\n\tUpdateCount int\n}\n\ntype WinGetPackage struct {\n\tName      string\n\tID        string\n\tCurrent   string\n\tAvailable string\n}\n\nfunc (w *WinGet) Template() string {\n\treturn \" \\uf409 {{ .UpdateCount }} \"\n}\n\nfunc (w *WinGet) Enabled() bool {\n\tif w.env.GOOS() != runtime.WINDOWS {\n\t\treturn false\n\t}\n\n\tif !w.env.HasCommand(\"winget\") {\n\t\treturn false\n\t}\n\n\toutput, err := w.env.RunCommand(\"winget\", \"upgrade\")\n\tif err != nil {\n\t\treturn false\n\t}\n\n\tw.Updates = w.parseWinGetOutput(output)\n\tw.UpdateCount = len(w.Updates)\n\n\treturn w.UpdateCount > 0\n}\n\nfunc (w *WinGet) parseWinGetOutput(output string) []WinGetPackage {\n\tvar packages []WinGetPackage\n\n\tlines := strings.Split(output, \"\\n\")\n\tseparatorIndex := -1\n\n\t// Find the separator line\n\tfor i, line := range lines {\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(line, \"---\") || strings.Contains(line, \"─\") {\n\t\t\tseparatorIndex = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\t// If no separator found, return empty\n\tif separatorIndex < 0 {\n\t\treturn packages\n\t}\n\n\t// The header line is right before the separator\n\tif separatorIndex == 0 {\n\t\treturn packages\n\t}\n\n\theaderLine := lines[separatorIndex-1]\n\n\t// Find column positions by detecting transitions from non-letter to letter\n\tcolumnIndices := findColumnIndices(headerLine)\n\n\t// We need at least 4 columns: Name, Id, Version, Available\n\tif len(columnIndices) < 4 {\n\t\treturn packages\n\t}\n\n\t// Second pass: process data lines after separator\n\tfor i := separatorIndex + 1; i < len(lines); i++ {\n\t\tline := lines[i]\n\n\t\tif line == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip footer lines\n\t\tif strings.Contains(line, \"upgrade\") && strings.Contains(line, \"available\") {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Skip lines that are too short to contain all fields\n\t\tif len(line) < columnIndices[3] {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Extract fields using column positions\n\t\tname := extractField(line, columnIndices[0], columnIndices[1])\n\t\tid := extractField(line, columnIndices[1], columnIndices[2])\n\t\tcurrent := extractField(line, columnIndices[2], columnIndices[3])\n\t\tavailable := extractField(line, columnIndices[3], columnIndices[4])\n\n\t\t// Skip if essential fields are empty\n\t\tif name == \"\" || id == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tpkg := WinGetPackage{\n\t\t\tName:      name,\n\t\t\tID:        id,\n\t\t\tCurrent:   current,\n\t\t\tAvailable: available,\n\t\t}\n\n\t\tpackages = append(packages, pkg)\n\t}\n\n\treturn packages\n}\n\nfunc findColumnIndices(headerLine string) []int {\n\tvar allIndices []int\n\tprevWasLetter := false\n\n\tfor i, char := range headerLine {\n\t\tisLetter := unicode.IsLetter(char)\n\n\t\tif isLetter && !prevWasLetter {\n\t\t\t// Found transition from non-letter to letter - this is a column start\n\t\t\tallIndices = append(allIndices, i)\n\t\t}\n\n\t\tprevWasLetter = isLetter\n\t}\n\n\t// Get the last 5 column positions (Name, Id, Version, Available, Source)\n\t// This handles cases where there's garbage before the actual header\n\tlastFive := allIndices[len(allIndices)-5:]\n\n\t// Make all positions relative to the first column position\n\tfirstColPos := lastFive[0]\n\trelativeIndices := make([]int, len(lastFive))\n\tfor i, pos := range lastFive {\n\t\trelativeIndices[i] = pos - firstColPos\n\t}\n\n\treturn relativeIndices\n}\n\nfunc extractField(line string, startIndex, endIndex int) string {\n\tif startIndex >= len(line) {\n\t\treturn \"\"\n\t}\n\tif endIndex > len(line) {\n\t\tendIndex = len(line)\n\t}\n\treturn strings.TrimSpace(line[startIndex:endIndex])\n}\n"
  },
  {
    "path": "src/segments/winget_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWinGet(t *testing.T) {\n\tcases := []struct {\n\t\tCommandError    error\n\t\tCase            string\n\t\tWinGetOutput    string\n\t\tGOOS            string\n\t\tExpectedCount   int\n\t\tHasCommand      bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase: \"No updates available\",\n\t\t\tWinGetOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nNo applicable updates found.`,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tCommandError:    nil,\n\t\t\tExpectedCount:   0,\n\t\t\tExpectedEnabled: false,\n\t\t\tHasCommand:      true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Multiple updates available\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCount:   3,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tHasCommand:      true,\n\t\t\tWinGetOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget\nNode.js            OpenJS.NodeJS               18.0.0    18.12.1   winget\nGit                Git.Git                     2.39.0    2.40.0    winget\n3 upgrades available.`,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Single update available\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCount:   1,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tHasCommand:      true,\n\t\t\tWinGetOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget`,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Non-Windows OS\",\n\t\t\tExpectedEnabled: false,\n\t\t\tGOOS:            runtime.LINUX,\n\t\t\tHasCommand:      true,\n\t\t},\n\t\t{\n\t\t\tCase:            \"WinGet command not found\",\n\t\t\tExpectedEnabled: false,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tHasCommand:      false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"Command execution error\",\n\t\t\tExpectedEnabled: false,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tHasCommand:      true,\n\t\t\tCommandError:    &runtime.CommandError{Err: \"command failed\"},\n\t\t},\n\t\t{\n\t\t\tCase:            \"Updates with Unicode separator\",\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedCount:   2,\n\t\t\tGOOS:            runtime.WINDOWS,\n\t\t\tHasCommand:      true,\n\t\t\tWinGetOutput: `Name               Id                          Version   Available Source\n─────────────────────────────────────────────────────────────────────────────────\nDocker Desktop     Docker.DockerDesktop        4.16.0    4.17.0    winget\nVisual Studio Code Microsoft.VisualStudioCode  1.75.0    1.76.0    winget`,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(tc.GOOS)\n\t\tenv.On(\"HasCommand\", \"winget\").Return(tc.HasCommand)\n\n\t\tif tc.CommandError != nil {\n\t\t\tenv.On(\"RunCommand\", \"winget\", []string{\"upgrade\"}).Return(\"\", tc.CommandError)\n\t\t} else if tc.HasCommand && tc.GOOS == runtime.WINDOWS {\n\t\t\tenv.On(\"RunCommand\", \"winget\", []string{\"upgrade\"}).Return(tc.WinGetOutput, nil)\n\t\t}\n\n\t\tw := &WinGet{}\n\t\tw.Init(options.Map{}, env)\n\n\t\tenabled := w.Enabled()\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif enabled {\n\t\t\tassert.Equal(t, tc.ExpectedCount, w.UpdateCount, tc.Case)\n\t\t\tassert.Equal(t, tc.ExpectedCount, len(w.Updates), tc.Case)\n\t\t}\n\t}\n}\n\nfunc TestWinGetParseOutput(t *testing.T) {\n\tcases := []struct {\n\t\tCase          string\n\t\tOutput        string\n\t\tExpectedFirst WinGetPackage\n\t\tExpectedCount int\n\t}{\n\t\t{\n\t\t\tCase: \"Standard output\",\n\t\t\tOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget\nNode.js            OpenJS.NodeJS               18.0.0    18.12.1   winget`,\n\t\t\tExpectedCount: 2,\n\t\t\tExpectedFirst: WinGetPackage{\n\t\t\t\tName:      \"Python 3.11\",\n\t\t\t\tID:        \"Python.Python.3.11\",\n\t\t\t\tCurrent:   \"3.11.0\",\n\t\t\t\tAvailable: \"3.11.5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Empty output\",\n\t\t\tOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------`,\n\t\t\tExpectedCount: 0,\n\t\t},\n\t\t{\n\t\t\tCase: \"Output with footer\",\n\t\t\tOutput: `Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget\n2 upgrades available.`,\n\t\t\tExpectedCount: 1,\n\t\t\tExpectedFirst: WinGetPackage{\n\t\t\t\tName:      \"Python 3.11\",\n\t\t\t\tID:        \"Python.Python.3.11\",\n\t\t\t\tCurrent:   \"3.11.0\",\n\t\t\t\tAvailable: \"3.11.5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Output with extra characters before header line\",\n\t\t\tOutput: `<THESE ARE SOME EXTRA CHARACTERS>Name               Id                          Version   Available Source\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget\n2 upgrades available.`,\n\t\t\tExpectedCount: 1,\n\t\t\tExpectedFirst: WinGetPackage{\n\t\t\t\tName:      \"Python 3.11\",\n\t\t\t\tID:        \"Python.Python.3.11\",\n\t\t\t\tCurrent:   \"3.11.0\",\n\t\t\t\tAvailable: \"3.11.5\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase: \"Spanish headers (localization test)\",\n\t\t\tOutput: `Nombre            Id                          Vers      Dispo  Origen\n-----------------------------------------------------------------------------------\nPython 3.11        Python.Python.3.11          3.11.0    3.11.5    winget\nNode.js            OpenJS.NodeJS               18.0.0    18.12.1   winget`,\n\t\t\tExpectedCount: 2,\n\t\t\tExpectedFirst: WinGetPackage{\n\t\t\t\tName:      \"Python 3.11\",\n\t\t\t\tID:        \"Python.Python.3.11\",\n\t\t\t\tCurrent:   \"3.11.0\",\n\t\t\t\tAvailable: \"3.11.5\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tw := &WinGet{}\n\t\tpackages := w.parseWinGetOutput(tc.Output)\n\n\t\tassert.Equal(t, tc.ExpectedCount, len(packages), tc.Case)\n\t\tif tc.ExpectedCount > 0 {\n\t\t\tassert.Equal(t, tc.ExpectedFirst.Name, packages[0].Name, tc.Case+\" - Name\")\n\t\t\tassert.Equal(t, tc.ExpectedFirst.ID, packages[0].ID, tc.Case+\" - ID\")\n\t\t\tassert.Equal(t, tc.ExpectedFirst.Current, packages[0].Current, tc.Case+\" - Current\")\n\t\t\tassert.Equal(t, tc.ExpectedFirst.Available, packages[0].Available, tc.Case+\" - Available\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/segments/winreg.go",
    "content": "package segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype WindowsRegistry struct {\n\tBase\n\n\tValue string\n}\n\nconst (\n\t// full path to the key; if ends in \\, gets \"(Default)\" key in that path\n\tRegistryPath options.Option = \"path\"\n\t// Fallback is the text to display if the key is not found\n\tFallback options.Option = \"fallback\"\n)\n\nfunc (wr *WindowsRegistry) Template() string {\n\treturn \" {{ .Value }} \"\n}\n\nfunc (wr *WindowsRegistry) Enabled() bool {\n\tif wr.env.GOOS() != runtime.WINDOWS {\n\t\treturn false\n\t}\n\n\tregistryPath := wr.options.String(RegistryPath, \"\")\n\twr.Value = wr.options.String(Fallback, \"\")\n\n\tregValue, err := wr.env.WindowsRegistryKeyValue(registryPath)\n\tif err == nil {\n\t\twr.Value = regValue.String\n\t\treturn true\n\t}\n\tif len(wr.Value) > 0 {\n\t\t// we have fallback value\n\t\treturn true\n\t}\n\treturn false\n}\n"
  },
  {
    "path": "src/segments/winreg_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWinReg(t *testing.T) {\n\tcases := []struct {\n\t\tErr             error\n\t\tgetWRKVOutput   *runtime.WindowsRegistryValue\n\t\tCaseDescription string\n\t\tPath            string\n\t\tFallback        string\n\t\tExpectedValue   string\n\t\tExpectedSuccess bool\n\t}{\n\t\t{\n\t\t\tCaseDescription: \"Error\",\n\t\t\tPath:            \"HKLLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\ProductName\",\n\t\t\tErr:             errors.New(\"no match\"),\n\t\t\tExpectedSuccess: false,\n\t\t},\n\t\t{\n\t\t\tCaseDescription: \"Value\",\n\t\t\tPath:            \"HKLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\InstallTime\",\n\t\t\tgetWRKVOutput:   &runtime.WindowsRegistryValue{ValueType: runtime.STRING, String: \"xbox\"},\n\t\t\tExpectedSuccess: true,\n\t\t\tExpectedValue:   \"xbox\",\n\t\t},\n\t\t{\n\t\t\tCaseDescription: \"Fallback value\",\n\t\t\tPath:            \"HKLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\InstallTime\",\n\t\t\tFallback:        \"cortana\",\n\t\t\tErr:             errors.New(\"no match\"),\n\t\t\tExpectedSuccess: true,\n\t\t\tExpectedValue:   \"cortana\",\n\t\t},\n\t\t{\n\t\t\tCaseDescription: \"Empty string value (no error) should display empty string even in presence of fallback\",\n\t\t\tPath:            \"HKLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\InstallTime\",\n\t\t\tgetWRKVOutput:   &runtime.WindowsRegistryValue{ValueType: runtime.STRING, String: \"\"},\n\t\t\tFallback:        \"anaconda\",\n\t\t\tExpectedSuccess: true,\n\t\t\tExpectedValue:   \"\",\n\t\t},\n\t\t{\n\t\t\tCaseDescription: \"Empty string value (no error) should display empty string\",\n\t\t\tPath:            \"HKLM\\\\Software\\\\Microsoft\\\\Windows NT\\\\CurrentVersion\\\\InstallTime\",\n\t\t\tgetWRKVOutput:   &runtime.WindowsRegistryValue{ValueType: runtime.STRING, String: \"\"},\n\t\t\tExpectedSuccess: true,\n\t\t\tExpectedValue:   \"\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"GOOS\").Return(runtime.WINDOWS)\n\t\tenv.On(\"WindowsRegistryKeyValue\", tc.Path).Return(tc.getWRKVOutput, tc.Err)\n\n\t\tprops := options.Map{\n\t\t\tRegistryPath: tc.Path,\n\t\t\tFallback:     tc.Fallback,\n\t\t}\n\n\t\tr := &WindowsRegistry{}\n\t\tr.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedSuccess, r.Enabled(), tc.CaseDescription)\n\t\tassert.Equal(t, tc.ExpectedValue, renderTemplate(env, r.Template(), r), tc.CaseDescription)\n\t}\n}\n"
  },
  {
    "path": "src/segments/withings.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/http\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\thttplib \"net/http\"\n\t\"net/url\"\n)\n\n// WithingsData struct contains the API data\ntype WithingsData struct {\n\tBody   *Body `json:\"body\"`\n\tStatus int   `json:\"status\"`\n}\n\ntype Body struct {\n\tMeasureGroups []*MeasureGroup `json:\"measuregrps\"`\n\tActivities    []*Activity     `json:\"activities\"`\n\tSeries        []*Series       `json:\"series\"`\n}\n\ntype MeasureGroup struct {\n\tComment  any        `json:\"comment\"`\n\tMeasures []*Measure `json:\"measures\"`\n}\n\ntype Measure struct {\n\tValue int `json:\"value\"`\n\tType  int `json:\"type\"`\n\tUnit  int `json:\"unit\"`\n}\n\ntype Series struct {\n\tStartdate int64 `json:\"startdate\"`\n\tEnddate   int64 `json:\"enddate\"`\n}\n\ntype Activity struct {\n\tDate          string `json:\"date\"`\n\tTimezone      string `json:\"timezone\"`\n\tDeviceid      string `json:\"deviceid\"`\n\tHashDeviceid  string `json:\"hash_deviceid\"`\n\tBrand         int    `json:\"brand\"`\n\tIsTracker     bool   `json:\"is_tracker\"`\n\tSteps         int    `json:\"steps\"`\n\tDistance      int    `json:\"distance\"`\n\tElevation     int    `json:\"elevation\"`\n\tSoft          int    `json:\"soft\"`\n\tModerate      int    `json:\"moderate\"`\n\tIntense       int    `json:\"intense\"`\n\tActive        int    `json:\"active\"`\n\tCalories      int    `json:\"calories\"`\n\tTotalcalories int    `json:\"totalcalories\"`\n\tHrAverage     int    `json:\"hr_average\"`\n\tHrMin         int    `json:\"hr_min\"`\n\tHrMax         int    `json:\"hr_max\"`\n\tHrZone0       int    `json:\"hr_zone_0\"`\n\tHrZone1       int    `json:\"hr_zone_1\"`\n\tHrZone2       int    `json:\"hr_zone_2\"`\n\tHrZone3       int    `json:\"hr_zone_3\"`\n}\n\n// WithingsAPI is a wrapper around http.Oauth\ntype WithingsAPI interface {\n\tGetMeasures(meastypes string) (*WithingsData, error)\n\tGetActivities(activities string) (*WithingsData, error)\n\tGetSleep() (*WithingsData, error)\n}\n\ntype withingsAPI struct {\n\t*http.OAuthRequest\n}\n\nfunc (w *withingsAPI) GetMeasures(meastypes string) (*WithingsData, error) {\n\ttwoWeeksAgo := strconv.FormatInt(time.Now().AddDate(0, 0, -14).Unix(), 10)\n\tformData := url.Values{\n\t\t\"meastypes\":  {meastypes},\n\t\t\"action\":     {\"getmeas\"},\n\t\t\"lastupdate\": {twoWeeksAgo},\n\t\t\"category\":   {\"1\"},\n\t}\n\treturn w.getWithingsData(\"https://wbsapi.withings.net/measure\", formData)\n}\n\nfunc (w *withingsAPI) GetActivities(activities string) (*WithingsData, error) {\n\tyesterday := time.Now().AddDate(0, 0, -1).Format(\"2006-01-02\")\n\ttoday := time.Now().Format(\"2006-01-02\")\n\tformData := url.Values{\n\t\t\"data_fields\":  {activities},\n\t\t\"action\":       {\"getactivity\"},\n\t\t\"startdateymd\": {yesterday},\n\t\t\"enddateymd\":   {today},\n\t\t\"category\":     {\"1\"},\n\t}\n\treturn w.getWithingsData(\"https://wbsapi.withings.net/v2/measure\", formData)\n}\n\nfunc (w *withingsAPI) GetSleep() (*WithingsData, error) {\n\ttoday := time.Now()\n\tyesterday := today.AddDate(0, 0, -1)\n\t// start from 21:00 yesterday\n\tstart := time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 21, 0, 0, 0, time.UTC).Unix()\n\t// end at 12PM today\n\tend := time.Date(today.Year(), today.Month(), today.Day(), 12, 0, 0, 0, time.UTC).Unix()\n\tformData := url.Values{\n\t\t\"action\":    {\"get\"},\n\t\t\"startdate\": {strconv.FormatInt(start, 10)},\n\t\t\"enddate\":   {strconv.FormatInt(end, 10)},\n\t}\n\treturn w.getWithingsData(\"https://wbsapi.withings.net/v2/sleep\", formData)\n}\n\nfunc (w *withingsAPI) getWithingsData(endpoint string, formData url.Values) (*WithingsData, error) {\n\tmodifiers := func(request *httplib.Request) {\n\t\trequest.Method = httplib.MethodPost\n\t\trequest.Header.Add(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\t}\n\n\tbody := strings.NewReader(formData.Encode())\n\n\tdata, err := http.OauthResult[*WithingsData](w.OAuthRequest, endpoint, body, modifiers)\n\tif data != nil && data.Status != 0 {\n\t\treturn nil, errors.New(\"Withings API error: \" + strconv.Itoa(data.Status))\n\t}\n\n\treturn data, err\n}\n\ntype Withings struct {\n\tBase\n\n\tapi        WithingsAPI\n\tSleepHours string\n\tWeight     float64\n\tSteps      int\n}\n\nconst (\n\tWithingsAccessTokenKey  = \"withings_access_token\"\n\tWithingsRefreshTokenKey = \"withings_refresh_token\"\n)\n\nfunc (w *Withings) Template() string {\n\treturn \"{{ if gt .Weight 0.0 }} {{ round .Weight 2 }}kg {{ end }}\"\n}\n\nfunc (w *Withings) Enabled() bool {\n\tw.initAPI()\n\n\tvar enabled bool\n\tif w.getActivities() {\n\t\tenabled = true\n\t}\n\tif w.getMeasures() {\n\t\tenabled = true\n\t}\n\tif w.getSleep() {\n\t\tenabled = true\n\t}\n\treturn enabled\n}\n\nfunc (w *Withings) initAPI() {\n\tif w.api != nil {\n\t\treturn\n\t}\n\n\toauth := &http.OAuthRequest{\n\t\tAccessTokenKey:  WithingsAccessTokenKey,\n\t\tRefreshTokenKey: WithingsRefreshTokenKey,\n\t\tSegmentName:     \"withings\",\n\t\tAccessToken:     w.options.Template(options.AccessToken, \"\", w),\n\t\tRefreshToken:    w.options.Template(options.RefreshToken, \"\", w),\n\t\tRequest: http.Request{\n\t\t\tEnv:         w.env,\n\t\t\tHTTPTimeout: w.options.Int(options.HTTPTimeout, options.DefaultHTTPTimeout),\n\t\t},\n\t}\n\n\tw.api = &withingsAPI{\n\t\tOAuthRequest: oauth,\n\t}\n}\n\nfunc (w *Withings) getMeasures() bool {\n\tdata, err := w.api.GetMeasures(\"1\")\n\tif err != nil {\n\t\treturn false\n\t}\n\t// no data\n\tif len(data.Body.MeasureGroups) == 0 || len(data.Body.MeasureGroups[0].Measures) == 0 {\n\t\treturn false\n\t}\n\tmeasure := data.Body.MeasureGroups[len(data.Body.MeasureGroups)-1].Measures[0]\n\tweight := measure.Value\n\tw.Weight = float64(weight) / math.Pow(10, math.Abs(float64(measure.Unit)))\n\treturn true\n}\n\nfunc (w *Withings) getActivities() bool {\n\tdata, err := w.api.GetActivities(\"steps\")\n\tif err != nil || len(data.Body.Activities) == 0 {\n\t\treturn false\n\t}\n\ttoday := time.Now().Format(\"2006-01-02\")\n\tfor _, activity := range data.Body.Activities {\n\t\tif activity.Date != today {\n\t\t\tcontinue\n\t\t}\n\t\tw.Steps = activity.Steps\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc (w *Withings) getSleep() bool {\n\tdata, err := w.api.GetSleep()\n\tif err != nil || len(data.Body.Series) == 0 {\n\t\treturn false\n\t}\n\tvar sleepStart, sleepEnd time.Time\n\tfor _, series := range data.Body.Series {\n\t\tstart := time.Unix(series.Startdate, 0)\n\t\tif sleepStart.IsZero() || start.Before(sleepStart) {\n\t\t\tsleepStart = start\n\t\t}\n\n\t\tend := time.Unix(series.Enddate, 0)\n\t\tif sleepStart.IsZero() || start.After(sleepEnd) {\n\t\t\tsleepEnd = end\n\t\t}\n\t}\n\n\tsleepHours := sleepEnd.Sub(sleepStart).Hours()\n\tw.SleepHours = fmt.Sprintf(\"%0.1f\", sleepHours)\n\n\treturn true\n}\n"
  },
  {
    "path": "src/segments/withings_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n\ttestify_ \"github.com/stretchr/testify/mock\"\n)\n\ntype mockedWithingsAPI struct {\n\ttestify_.Mock\n}\n\nfunc (s *mockedWithingsAPI) GetMeasures(meastypes string) (*WithingsData, error) {\n\targs := s.Called(meastypes)\n\treturn args.Get(0).(*WithingsData), args.Error(1)\n}\n\nfunc (s *mockedWithingsAPI) GetActivities(activities string) (*WithingsData, error) {\n\targs := s.Called(activities)\n\treturn args.Get(0).(*WithingsData), args.Error(1)\n}\n\nfunc (s *mockedWithingsAPI) GetSleep() (*WithingsData, error) {\n\targs := s.Called()\n\treturn args.Get(0).(*WithingsData), args.Error(1)\n}\n\nfunc TestWithingsSegment(t *testing.T) {\n\tcases := []struct {\n\t\tMeasuresError   error\n\t\tActivitiesError error\n\t\tSleepError      error\n\t\tWithingsData    *WithingsData\n\t\tCase            string\n\t\tExpectedString  string\n\t\tTemplate        string\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"Error\",\n\t\t\tMeasuresError:   errors.New(\"error\"),\n\t\t\tActivitiesError: errors.New(\"error\"),\n\t\t\tSleepError:      errors.New(\"error\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase: \"Only Measures data\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{\n\t\t\t\t\tMeasureGroups: []*MeasureGroup{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMeasures: []*Measure{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tValue: 7077,\n\t\t\t\t\t\t\t\t\tUnit:  -2,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tActivitiesError: errors.New(\"error\"),\n\t\t\tSleepError:      errors.New(\"error\"),\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"70.77kg\",\n\t\t},\n\t\t{\n\t\t\tCase: \"Multiple Measuring Groups, only Measures data\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{\n\t\t\t\t\tMeasureGroups: []*MeasureGroup{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMeasures: []*Measure{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tValue: 7123,\n\t\t\t\t\t\t\t\t\tUnit:  -2,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tMeasures: []*Measure{\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tValue: 7754,\n\t\t\t\t\t\t\t\t\tUnit:  -2,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tActivitiesError: errors.New(\"error\"),\n\t\t\tSleepError:      errors.New(\"error\"),\n\t\t\tExpectedEnabled: true,\n\t\t\tExpectedString:  \"77.54kg\",\n\t\t},\n\t\t{\n\t\t\tCase: \"Measures, no data\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{},\n\t\t\t},\n\t\t\tActivitiesError: errors.New(\"error\"),\n\t\t\tSleepError:      errors.New(\"error\"),\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Activities\",\n\t\t\tTemplate:       \"{{ .Steps }} steps\",\n\t\t\tExpectedString: \"7077 steps\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{\n\t\t\t\t\tActivities: []*Activity{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSteps: 5066,\n\t\t\t\t\t\t\tDate:  time.Now().AddDate(0, 0, -1).Format(\"2006-01-02\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSteps: 7077,\n\t\t\t\t\t\t\tDate:  time.Now().Format(\"2006-01-02\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMeasuresError:   errors.New(\"error\"),\n\t\t\tSleepError:      errors.New(\"error\"),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Sleep\",\n\t\t\tTemplate:       \"{{ .SleepHours }}hr\",\n\t\t\tExpectedString: \"11.8hr\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{\n\t\t\t\t\tSeries: []*Series{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tStartdate: 1594159200,\n\t\t\t\t\t\t\tEnddate:   1594201500,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMeasuresError:   errors.New(\"error\"),\n\t\t\tActivitiesError: errors.New(\"error\"),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t\t{\n\t\t\tCase:           \"Sleep and Activity\",\n\t\t\tTemplate:       \"{{ .Steps }} steps with {{ .SleepHours }}hr of sleep\",\n\t\t\tExpectedString: \"976 steps with 11.8hr of sleep\",\n\t\t\tWithingsData: &WithingsData{\n\t\t\t\tBody: &Body{\n\t\t\t\t\tSeries: []*Series{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tStartdate: 1594159200,\n\t\t\t\t\t\t\tEnddate:   1594201500,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tActivities: []*Activity{\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tSteps: 976,\n\t\t\t\t\t\t\tDate:  time.Now().Format(\"2006-01-02\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tMeasuresError:   errors.New(\"error\"),\n\t\t\tExpectedEnabled: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tapi := &mockedWithingsAPI{}\n\t\tapi.On(\"GetMeasures\", \"1\").Return(tc.WithingsData, tc.MeasuresError)\n\t\tapi.On(\"GetActivities\", \"steps\").Return(tc.WithingsData, tc.ActivitiesError)\n\t\tapi.On(\"GetSleep\").Return(tc.WithingsData, tc.SleepError)\n\n\t\twithings := &Withings{\n\t\t\tapi: api,\n\t\t}\n\t\twithings.Init(options.Map{}, &mock.Environment{})\n\n\t\tenabled := withings.Enabled()\n\t\tassert.Equal(t, tc.ExpectedEnabled, enabled, tc.Case)\n\t\tif !enabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tif tc.Template == \"\" {\n\t\t\ttc.Template = withings.Template()\n\t\t}\n\n\t\tvar got = renderTemplate(&mock.Environment{}, tc.Template, withings)\n\t\tassert.Equal(t, tc.ExpectedString, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/xmake.go",
    "content": "package segments\n\ntype XMake struct {\n\tLanguage\n}\n\nfunc (x *XMake) Template() string {\n\treturn languageTemplate\n}\n\nfunc (x *XMake) Enabled() bool {\n\tx.extensions = []string{\"xmake.lua\"}\n\tx.tooling = map[string]*cmd{\n\t\t\"xmake\": {\n\t\t\texecutable: \"xmake\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `xmake v(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tx.defaultTooling = []string{\"xmake\"}\n\n\treturn x.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/xmake_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestXMake(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"XMake 2.7.2-dev\", ExpectedString: \"2.7.2\", Version: \"xmake v2.7.2+dev.605b8e3e0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"xmake\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"xmake.lua\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tx := &XMake{}\n\t\tx.Init(props, env)\n\t\tassert.True(t, x.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, x.Template(), x), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/yarn.go",
    "content": "package segments\n\ntype Yarn struct {\n\tLanguage\n}\n\nfunc (n *Yarn) Template() string {\n\treturn \" \\ue6a7 {{.Full}} \"\n}\n\nfunc (n *Yarn) Enabled() bool {\n\tn.extensions = []string{\"package.json\", \"yarn.lock\"}\n\tn.tooling = map[string]*cmd{\n\t\t\"yarn\": {\n\t\t\texecutable: \"yarn\",\n\t\t\targs:       []string{\"--version\"},\n\t\t\tregex:      `(?P<version>((?P<major>[0-9]+).(?P<minor>[0-9]+).(?P<patch>[0-9]+)))`,\n\t\t},\n\t}\n\tn.defaultTooling = []string{\"yarn\"}\n\tn.versionURLTemplate = \"https://github.com/yarnpkg/berry/releases/tag/v{{ .Full }}\"\n\n\treturn n.Language.Enabled()\n}\n"
  },
  {
    "path": "src/segments/yarn_test.go",
    "content": "package segments\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/alecthomas/assert\"\n)\n\nfunc TestYarn(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tExpectedString string\n\t\tVersion        string\n\t}{\n\t\t{Case: \"1.0.0\", ExpectedString: \"\\ue6a7 1.0.0\", Version: \"1.0.0\"},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"yarn\",\n\t\t\tversionParam:  \"--version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"package.json\",\n\t\t}\n\t\tenv, props := getMockedLanguageEnv(params)\n\t\tyarn := &Yarn{}\n\t\tyarn.Init(props, env)\n\t\tassert.True(t, yarn.Enabled(), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, yarn.Template(), yarn), fmt.Sprintf(\"Failed in case: %s\", tc.Case))\n\t}\n}\n"
  },
  {
    "path": "src/segments/ytm.go",
    "content": "package segments\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\thttplib \"net/http\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/auth\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\nconst (\n\tytmdaStatusURL = auth.YTMDABASEURL + \"/state\"\n)\n\ntype Ytm struct {\n\tBase\n\n\tMusicPlayer\n}\n\nfunc (y *Ytm) Template() string {\n\treturn \" {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \"\n}\n\nfunc (y *Ytm) Enabled() bool {\n\terr := y.setStatus()\n\tif err != nil {\n\t\tlog.Error(err)\n\t}\n\n\treturn err == nil\n}\n\ntype ytmdaStatusResponse struct {\n\tVideo struct {\n\t\tAuthor string `json:\"author\"`\n\t\tTitle  string `json:\"title\"`\n\t} `json:\"video\"`\n\tPlayer struct {\n\t\tTrackState int  `json:\"trackState\"`\n\t\tAdPlaying  bool `json:\"adPlaying\"`\n\t} `json:\"player\"`\n}\n\nfunc (y *Ytm) setStatus() error {\n\ttoken, OK := cache.Get[string](cache.Device, auth.YTMDATOKEN)\n\tif !OK || token == \"\" {\n\t\treturn errors.New(\"YTMDA token not found, please authenticate using `oh-my-posh auth ytmda`\")\n\t}\n\n\tstatus, err := y.requestStatus(token)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tswitch status.Player.TrackState {\n\tcase 1, 2: // playing or buffering\n\t\ty.Status = playing\n\t\ty.Icon = y.options.String(PlayingIcon, \"\\uf04b \")\n\tcase -1: // stopped\n\t\ty.Status = stopped\n\t\ty.Icon = y.options.String(StoppedIcon, \"\\uf04d \")\n\tdefault: // paused\n\t\ty.Status = paused\n\t\ty.Icon = y.options.String(PausedIcon, \"\\uf04c \")\n\t}\n\n\tif status.Player.AdPlaying {\n\t\tad := y.options.String(AdIcon, \"\\ueebb \")\n\t\ty.Icon = ad + y.Icon\n\t}\n\n\ty.Artist = status.Video.Author\n\ty.Track = status.Video.Title\n\n\treturn nil\n}\n\nfunc (y *Ytm) requestStatus(token string) (*ytmdaStatusResponse, error) {\n\tsetHeaders := func(request *httplib.Request) {\n\t\trequest.Header.Set(\"Authorization\", token)\n\t\trequest.Header.Set(\"Content-Type\", \"application/json\")\n\t}\n\n\thttpTimeout := y.options.Int(options.HTTPTimeout, 5000)\n\tresponse, err := y.env.HTTPRequest(ytmdaStatusURL, nil, httpTimeout, setHeaders)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar result ytmdaStatusResponse\n\terr = json.Unmarshal(response, &result)\n\treturn &result, err\n}\n"
  },
  {
    "path": "src/segments/ytm_test.go",
    "content": "package segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cli/auth\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestYTM(t *testing.T) {\n\tcases := []struct {\n\t\tHTTPError       error\n\t\tCase            string\n\t\tJSONResponse    string\n\t\tExpectedString  string\n\t\tHasToken        bool\n\t\tExpectedEnabled bool\n\t}{\n\t\t{\n\t\t\tCase:            \"no token in cache\",\n\t\t\tHasToken:        false,\n\t\t\tExpectedEnabled: false,\n\t\t},\n\t\t{\n\t\t\tCase:            \"no response\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: false,\n\t\t\tHTTPError:       assert.AnError,\n\t\t},\n\t\t{\n\t\t\tCase:            \"empty response\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: false,\n\t\t\tJSONResponse:    \"\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"invalid response\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: false,\n\t\t\tJSONResponse:    \"invalid json\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"paused\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tJSONResponse:    `{\"video\": {\"author\": \"Author\", \"title\": \"Title\"}, \"player\": {\"trackState\": 0, \"adPlaying\": false}}`,\n\t\t\tExpectedString:  \"Paused Author - Title\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"playing\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tJSONResponse:    `{\"video\": {\"author\": \"Author\", \"title\": \"Title\"}, \"player\": {\"trackState\": 1, \"adPlaying\": false}}`,\n\t\t\tExpectedString:  \"Playing Author - Title\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"buffering\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tJSONResponse:    `{\"video\": {\"author\": \"Author\", \"title\": \"Title\"}, \"player\": {\"trackState\": 2, \"adPlaying\": false}}`,\n\t\t\tExpectedString:  \"Playing Author - Title\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"stopped\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tJSONResponse:    `{\"video\": {\"author\": \"Author\", \"title\": \"Title\"}, \"player\": {\"trackState\": -1, \"adPlaying\": false}}`,\n\t\t\tExpectedString:  \"Stopped\",\n\t\t},\n\t\t{\n\t\t\tCase:            \"ad playing\",\n\t\t\tHasToken:        true,\n\t\t\tExpectedEnabled: true,\n\t\t\tJSONResponse:    `{\"video\": {\"author\": \"Author\", \"title\": \"Title\"}, \"player\": {\"trackState\": 1, \"adPlaying\": true}}`,\n\t\t\tExpectedString:  \"Ad Playing Author - Title\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"HTTPRequest\", ytmdaStatusURL).Return([]byte(tc.JSONResponse), tc.HTTPError)\n\n\t\tif tc.HasToken {\n\t\t\tcache.Set(cache.Device, auth.YTMDATOKEN, \"test_token\", cache.INFINITE)\n\t\t}\n\n\t\tprops := options.Map{\n\t\t\tStoppedIcon: \"Stopped \",\n\t\t\tPlayingIcon: \"Playing \",\n\t\t\tPausedIcon:  \"Paused \",\n\t\t\tAdIcon:      \"Ad \",\n\t\t}\n\n\t\tytm := new(Ytm)\n\t\tytm.Init(props, env)\n\n\t\tassert.Equal(t, tc.ExpectedEnabled, ytm.Enabled(), tc.Case)\n\t\tcache.DeleteAll(cache.Device)\n\n\t\tif !tc.ExpectedEnabled {\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, ytm.Template(), ytm), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/segments/zig.go",
    "content": "package segments\n\ntype Zig struct {\n\tLanguage\n}\n\nfunc (zig *Zig) Template() string {\n\treturn languageTemplate\n}\n\nfunc (zig *Zig) Enabled() bool {\n\tzig.extensions = []string{\"*.zig\", \"*.zon\"}\n\tzig.projectFiles = []string{\"build.zig\"}\n\tzig.tooling = map[string]*cmd{\n\t\t\"zig\": {\n\t\t\texecutable: \"zig\",\n\t\t\targs:       []string{\"version\"},\n\t\t\tregex:      `(?P<version>(?P<major>0|[1-9]\\d*)\\.(?P<minor>0|[1-9]\\d*)\\.(?P<patch>0|[1-9]\\d*)(?:-(?P<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)`, //nolint:lll\n\t\t},\n\t}\n\tzig.defaultTooling = []string{\"zig\"}\n\n\tzig.versionURLTemplate = \"https://ziglang.org/download/{{ .Major }}.{{ .Minor }}.{{ .Patch }}/release-notes.html\"\n\n\treturn zig.Language.Enabled()\n}\n\nfunc (zig *Zig) InProjectDir() bool {\n\treturn zig.projectRoot != nil\n}\n"
  },
  {
    "path": "src/segments/zig_test.go",
    "content": "package segments\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestZig(t *testing.T) {\n\tcases := []struct {\n\t\tCase           string\n\t\tVersion        string\n\t\tExpectedString string\n\t\tExpectedURL    string\n\t\tInProjectDir   bool\n\t}{\n\t\t{\n\t\t\tCase:           \"zig 0.13.0 - not in project dir\",\n\t\t\tVersion:        \"0.13.0\",\n\t\t\tInProjectDir:   false,\n\t\t\tExpectedString: \"0.13.0\",\n\t\t\tExpectedURL:    \"https://ziglang.org/download/0.13.0/release-notes.html\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"zig 0.12.0-dev.2063+804cee3b9 - not in project dir\",\n\t\t\tVersion:        \"0.12.0-dev.2063+804cee3b9\",\n\t\t\tInProjectDir:   false,\n\t\t\tExpectedString: \"0.12.0-dev.2063+804cee3b9\",\n\t\t\tExpectedURL:    \"https://ziglang.org/download/0.12.0/release-notes.html\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"zig 0.13.0 - in project dir\",\n\t\t\tVersion:        \"0.13.0\",\n\t\t\tInProjectDir:   true,\n\t\t\tExpectedString: \"0.13.0\",\n\t\t\tExpectedURL:    \"https://ziglang.org/download/0.13.0/release-notes.html\",\n\t\t},\n\t\t{\n\t\t\tCase:           \"zig 0.12.0-dev.2063+804cee3b9 - in project dir\",\n\t\t\tVersion:        \"0.12.0-dev.2063+804cee3b9\",\n\t\t\tInProjectDir:   true,\n\t\t\tExpectedString: \"0.12.0-dev.2063+804cee3b9\",\n\t\t\tExpectedURL:    \"https://ziglang.org/download/0.12.0/release-notes.html\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tparams := &mockedLanguageParams{\n\t\t\tcmd:           \"zig\",\n\t\t\tversionParam:  \"version\",\n\t\t\tversionOutput: tc.Version,\n\t\t\textension:     \"*.zig\",\n\t\t}\n\n\t\tenv, props := getMockedLanguageEnv(params)\n\n\t\tdummyDir := &runtime.FileInfo{}\n\n\t\tif tc.InProjectDir {\n\t\t\tenv.On(\"HasParentFilePath\", \"build.zig\", false).Return(dummyDir, nil)\n\t\t} else {\n\t\t\tenv.On(\"HasParentFilePath\", \"build.zig\", false).Return(dummyDir, errors.New(\"build.zig not found\"))\n\t\t}\n\n\t\tzig := &Zig{}\n\t\tzig.Init(props, env)\n\n\t\tassert.True(t, zig.Enabled(), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedString, renderTemplate(env, zig.Template(), zig), tc.Case)\n\t\tassert.Equal(t, tc.ExpectedURL, renderTemplate(env, zig.URL, zig), tc.Case)\n\t\tassert.Equal(t, tc.InProjectDir, zig.InProjectDir(), tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/shell/bash.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.bash\nvar bashInit string\n\nfunc (f Features) Bash() Code {\n\tswitch f {\n\tcase CursorPositioning:\n\t\treturn unixCursorPositioning\n\tcase FTCSMarks:\n\t\treturn unixFTCSMarks\n\tcase Upgrade:\n\t\treturn unixUpgrade\n\tcase Notice:\n\t\treturn unixNotice\n\tcase RPrompt:\n\t\tif !bashBLEsession {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn `bleopt prompt_rps1='$(\n\t\"$_omp_executable\" print right \\\n\t\t--save-cache \\\n\t\t--shell=bash \\\n\t\t--shell-version=\"$BASH_VERSION\" \\\n\t\t--status=\"$_omp_status\" \\\n\t\t--pipestatus=\"${_omp_pipestatus[*]}\" \\\n\t\t--no-status=\"$_omp_no_status\" \\\n\t\t--execution-time=\"$_omp_execution_time\" \\\n\t\t--stack-count=\"$_omp_stack_count\" \\\n\t\t--terminal-width=\"${COLUMNS-0}\" \\\n\t\t--escape=false\n)'`\n\tcase Transient:\n\t\tif !bashBLEsession {\n\t\t\treturn \"\"\n\t\t}\n\n\t\treturn `bleopt prompt_ps1_transient=always\nbleopt prompt_ps1_final='$(\n    \"$_omp_executable\" print transient \\\n        --shell=bash \\\n        --shell-version=\"$BASH_VERSION\" \\\n        --escape=false\n)'`\n\tcase PromptMark, PoshGit, Azure, LineError, Jobs, Tooltips, Async, Streaming, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc QuotePosixStr(str string) string {\n\tif str == \"\" {\n\t\treturn \"''\"\n\t}\n\n\treturn fmt.Sprintf(\"$'%s'\", strings.NewReplacer(`\\`, `\\\\`, \"'\", `\\'`).Replace(str))\n}\n"
  },
  {
    "path": "src/shell/bash_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBashFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(BASH).String(\"// these are the features\")\n\n\twant := `// these are the features\n_omp_ftcs_marks=1\n\"$_omp_executable\" upgrade --auto\n\"$_omp_executable\" notice\n_omp_cursor_positioning=1`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestBashFeaturesWithBLE(t *testing.T) {\n\tbashBLEsession = true\n\n\tgot := allFeatures.Lines(BASH).String(\"// these are the features\")\n\n\twant := `// these are the features\nbleopt prompt_ps1_transient=always\nbleopt prompt_ps1_final='$(\n    \"$_omp_executable\" print transient \\\n        --shell=bash \\\n        --shell-version=\"$BASH_VERSION\" \\\n        --escape=false\n)'\n_omp_ftcs_marks=1\n\"$_omp_executable\" upgrade --auto\n\"$_omp_executable\" notice\nbleopt prompt_rps1='$(\n\t\"$_omp_executable\" print right \\\n\t\t--save-cache \\\n\t\t--shell=bash \\\n\t\t--shell-version=\"$BASH_VERSION\" \\\n\t\t--status=\"$_omp_status\" \\\n\t\t--pipestatus=\"${_omp_pipestatus[*]}\" \\\n\t\t--no-status=\"$_omp_no_status\" \\\n\t\t--execution-time=\"$_omp_execution_time\" \\\n\t\t--stack-count=\"$_omp_stack_count\" \\\n\t\t--terminal-width=\"${COLUMNS-0}\" \\\n\t\t--escape=false\n)'\n_omp_cursor_positioning=1`\n\n\tassert.Equal(t, want, got)\n\n\tbashBLEsession = false\n}\n\nfunc TestQuotePosixStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"''\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `$'/tmp/\"omp\\'s dir\"/oh-my-posh'`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `$'C:/tmp\\\\omp\\'s dir/oh-my-posh.exe'`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, QuotePosixStr(tc.str), fmt.Sprintf(\"QuotePosixStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/cmd.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.lua\nvar cmdInit string\n\nfunc (f Features) Cmd() Code {\n\tswitch f {\n\tcase Transient:\n\t\treturn \"transient_enabled = true\"\n\tcase RPrompt:\n\t\treturn \"rprompt_enabled = true\"\n\tcase FTCSMarks:\n\t\treturn \"ftcs_marks_enabled = true\"\n\tcase Tooltips:\n\t\treturn \"enable_tooltips()\"\n\tcase Upgrade:\n\t\treturn `os.execute(string.format('\"%s\" upgrade --auto', omp_executable))`\n\tcase Notice:\n\t\treturn `os.execute(string.format('\"%s\" notice', omp_executable))`\n\tcase PromptMark, PoshGit, Azure, LineError, Jobs, CursorPositioning, Async, Streaming, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc escapeLuaStr(str string) string {\n\tif str == \"\" {\n\t\treturn str\n\t}\n\t// We only replace a minimal set of special characters with corresponding escape sequences, without adding surrounding quotes.\n\t// That way the result can be later quoted with either single or double quotes in a Lua script.\n\treturn strings.NewReplacer(\n\t\t`\\`, `\\\\`,\n\t\t\"'\", `\\'`,\n\t\t`\"`, `\\\"`,\n\t\t\"\\n\", `\\n`,\n\t\t\"\\r\", `\\r`,\n\t).Replace(str)\n}\n"
  },
  {
    "path": "src/shell/cmd_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestCmdFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(CMD).String(\"// these are the features\")\n\n\twant := `// these are the features\nenable_tooltips()\ntransient_enabled = true\nftcs_marks_enabled = true\nos.execute(string.format('\"%s\" upgrade --auto', omp_executable))\nos.execute(string.format('\"%s\" notice', omp_executable))\nrprompt_enabled = true`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestEscapeLuaStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `/tmp/\\\"omp\\'s dir\\\"/oh-my-posh`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `C:/tmp\\\\omp\\'s dir/oh-my-posh.exe`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, escapeLuaStr(tc.str), fmt.Sprintf(\"escapeLuaStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/code.go",
    "content": "package shell\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\ntype Code string\n\nconst (\n\tunixFTCSMarks         Code = \"_omp_ftcs_marks=1\"\n\tunixCursorPositioning Code = \"_omp_cursor_positioning=1\"\n\tunixUpgrade           Code = `\"$_omp_executable\" upgrade --auto`\n\tunixNotice            Code = `\"$_omp_executable\" notice`\n)\n\nfunc (c Code) Indent(spaces int) Code {\n\treturn Code(strings.Repeat(\" \", spaces) + string(c))\n}\n\ntype Lines []Code\n\nfunc (l Lines) String(script string) string {\n\tbuilder := text.NewBuilder()\n\n\tbuilder.WriteString(script)\n\tbuilder.WriteString(\"\\n\")\n\n\tfor i, line := range l {\n\t\tbuilder.WriteString(string(line))\n\n\t\t// add newline if not last line\n\t\tif i < len(l)-1 {\n\t\t\tbuilder.WriteString(\"\\n\")\n\t\t}\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "src/shell/constants.go",
    "content": "package shell\n\nconst (\n\tZSH     = \"zsh\"\n\tBASH    = \"bash\"\n\tPWSH    = \"pwsh\"\n\tFISH    = \"fish\"\n\tCMD     = \"cmd\"\n\tNU      = \"nu\"\n\tGENERIC = \"shell\"\n\tELVISH  = \"elvish\"\n\tXONSH   = \"xonsh\"\n\tCLAUDE  = \"claude\"\n)\n"
  },
  {
    "path": "src/shell/dsc.go",
    "content": "package shell\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/dsc\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/cmd\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\nfunc init() {\n\tgob.Register([]*Shell{})\n}\n\nconst (\n\tinitCommandRegex = `oh-my-posh(?:\\.exe)?\\s+init`\n)\n\nfunc DSC() *dsc.Resource[*Shell] {\n\treturn &dsc.Resource[*Shell]{}\n}\n\ntype Shell struct {\n\tCommand string `json:\"command,omitempty\" jsonschema:\"title=Command,description=The oh-my-posh init command to run\"`\n\tName    string `json:\"name,omitempty\" jsonschema:\"title=Shell name,description=The name of the shell\"`\n}\n\nfunc (s *Shell) Equal(shell *Shell) bool {\n\tif shell == nil {\n\t\treturn false\n\t}\n\n\treturn s.Name == shell.Name\n}\n\nfunc (s *Shell) Resolve() (*Shell, bool) {\n\treturn nil, false\n}\n\nfunc (s *Shell) Apply() error {\n\tif s.Command == \"\" {\n\t\treturn nil\n\t}\n\n\tlog.Debug(\"applying shell configuration with command: %s\", s.Command)\n\n\t// Get the shell configuration file path\n\tconfigPath, err := s.getShellConfigPath()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get shell config path: %w\", err)\n\t}\n\n\tif err := s.validateShellConfigPath(configPath); err != nil {\n\t\treturn err\n\t}\n\n\t// Read current configuration\n\tcontent, err := os.ReadFile(configPath)\n\tif err != nil {\n\t\tlog.Debug(\"failed to read shell config file\")\n\t\treturn err\n\t}\n\n\tcontentStr, updated := s.updateShellConfig(string(content))\n\tif !updated {\n\t\tlog.Debug(\"shell config already up to date, skipping write\")\n\t\treturn nil\n\t}\n\n\treturn os.WriteFile(configPath, []byte(contentStr), 0644)\n}\n\nfunc (s *Shell) getShellConfigPath() (string, error) {\n\thome := path.Home()\n\tif home == \"\" {\n\t\treturn \"\", fmt.Errorf(\"failed to get home directory\")\n\t}\n\n\tswitch s.Name {\n\tcase BASH:\n\t\tbashrc := filepath.Join(home, \".bashrc\")\n\t\tif _, err := os.Stat(bashrc); err == nil {\n\t\t\treturn bashrc, nil\n\t\t}\n\n\t\treturn filepath.Join(home, \".bash_profile\"), nil\n\tcase ZSH:\n\t\treturn filepath.Join(home, \".zshrc\"), nil\n\tcase FISH:\n\t\tconfigDir := filepath.Join(home, \".config\", \"fish\")\n\t\treturn filepath.Join(configDir, \"config.fish\"), nil\n\tcase PWSH:\n\t\treturn cmd.Run(s.Name, \"-NoProfile\", \"-Command\", \"$PROFILE\")\n\tcase NU:\n\t\treturn cmd.Run(\"nu\", \"-c\", \"$nu.config-path\")\n\tcase ELVISH:\n\t\treturn filepath.Join(home, \".elvish\", \"rc.elv\"), nil\n\tcase XONSH:\n\t\treturn filepath.Join(home, \".xonshrc\"), nil\n\tdefault:\n\t\treturn \"\", fmt.Errorf(\"unsupported shell type: %s\", s.Name)\n\t}\n}\n\nfunc (s *Shell) validateShellConfigPath(configPath string) error {\n\tlog.Debug(\"validating shell config path:\", configPath)\n\n\t_, err := os.Stat(configPath)\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn err\n\t}\n\n\tif !os.IsNotExist(err) {\n\t\treturn nil\n\t}\n\n\tlog.Debug(\"shell config file does not exist\")\n\n\tif err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {\n\t\tlog.Debug(\"failed to create shell config directory\")\n\t\treturn err\n\t}\n\n\tif err := os.WriteFile(configPath, []byte(\"\"), 0644); err != nil {\n\t\tlog.Debug(\"failed to create shell config file\")\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *Shell) updateShellConfig(content string) (string, bool) {\n\tlog.Debug(\"current shell config content:\\n\", content)\n\n\tlines := strings.Split(content, \"\\n\")\n\tinitLinePos := s.getLastInitLinePosition(lines)\n\n\tif initLinePos < 0 {\n\t\treturn s.addInitLine(content), true\n\t}\n\n\tinitLineStr := lines[initLinePos]\n\tshellCommand := s.shellCommand()\n\n\t// validate if we have the same command\n\tif strings.Contains(initLineStr, shellCommand) {\n\t\tlog.Debug(\"oh-my-posh already correctly configured\")\n\t\treturn content, false\n\t}\n\n\tlines[initLinePos] = whitespacePrefix(initLineStr) + shellCommand\n\tcontent = strings.Join(lines, \"\\n\")\n\tlog.Debug(\"updated shell config content:\\n\", content)\n\n\treturn content, true\n}\n\nfunc (s *Shell) addInitLine(content string) string {\n\tlog.Debug(\"oh-my-posh not initialized, adding initialization\")\n\n\t// Add the initialization command to the end of the file\n\tif !strings.HasSuffix(content, \"\\n\") {\n\t\tcontent += \"\\n\"\n\t}\n\tcontent += s.shellCommand() + \"\\n\"\n\n\treturn content\n}\n\nfunc (s *Shell) getLastInitLinePosition(lines []string) int {\n\tfor i := len(lines) - 1; i >= 0; i-- {\n\t\tline := lines[i]\n\t\tif regex.MatchString(initCommandRegex, line) && !strings.HasPrefix(strings.TrimSpace(line), \"#\") {\n\t\t\treturn i\n\t\t}\n\t}\n\n\treturn -1\n}\n\nfunc (s *Shell) shellCommand() string {\n\tswitch s.Name {\n\tcase BASH, ZSH:\n\t\treturn fmt.Sprintf(`eval \"$(%s)\"`, s.Command)\n\tcase FISH:\n\t\treturn s.Command + \" | source\"\n\tcase PWSH:\n\t\treturn s.Command + \" | Invoke-Expression\"\n\tcase ELVISH:\n\t\treturn fmt.Sprintf(`eval (%s)`, s.Command)\n\tcase XONSH:\n\t\treturn fmt.Sprintf(`execx($(%s))`, s.Command)\n\tdefault:\n\t\treturn s.Command\n\t}\n}\n\nfunc whitespacePrefix(s string) string {\n\tvar builder strings.Builder\n\n\tfor _, char := range s {\n\t\tif char == ' ' || char == '\\t' {\n\t\t\tbuilder.WriteRune(char)\n\t\t\tcontinue\n\t\t}\n\n\t\tbreak\n\t}\n\n\treturn builder.String()\n}\n"
  },
  {
    "path": "src/shell/dsc_test.go",
    "content": "package shell\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWhitespacePrefix(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tinput    string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname:     \"no whitespace\",\n\t\t\tinput:    \"hello world\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"bash initialization line\",\n\t\t\tinput:    `eval \"$(oh-my-posh init bash)\"`,\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"only spaces\",\n\t\t\tinput:    \"   \",\n\t\t\texpected: \"   \",\n\t\t},\n\t\t{\n\t\t\tname:     \"indented bash initialization\",\n\t\t\tinput:    `    eval \"$(oh-my-posh init bash)\"`,\n\t\t\texpected: \"    \",\n\t\t},\n\t\t{\n\t\t\tname:     \"only tabs\",\n\t\t\tinput:    \"\\t\\t\\t\",\n\t\t\texpected: \"\\t\\t\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"tab indented initialization\",\n\t\t\tinput:    \"\\teval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\texpected: \"\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"mixed spaces and tabs\",\n\t\t\tinput:    \" \\t \\t\",\n\t\t\texpected: \" \\t \\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"spaces before text\",\n\t\t\tinput:    \"    hello world\",\n\t\t\texpected: \"    \",\n\t\t},\n\t\t{\n\t\t\tname:     \"commented out initialization\",\n\t\t\tinput:    \"# eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"tabs before text\",\n\t\t\tinput:    \"\\t\\thello world\",\n\t\t\texpected: \"\\t\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"indented comment\",\n\t\t\tinput:    \"    # eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\texpected: \"    \",\n\t\t},\n\t\t{\n\t\t\tname:     \"mixed whitespace before text\",\n\t\t\tinput:    \" \\t  \\teval command\",\n\t\t\texpected: \" \\t  \\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"powershell initialization\",\n\t\t\tinput:    \"oh-my-posh init pwsh | Invoke-Expression\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"single space\",\n\t\t\tinput:    \" hello\",\n\t\t\texpected: \" \",\n\t\t},\n\t\t{\n\t\t\tname:     \"fish initialization\",\n\t\t\tinput:    \"oh-my-posh init fish | source\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"single tab\",\n\t\t\tinput:    \"\\thello\",\n\t\t\texpected: \"\\t\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty string\",\n\t\t\tinput:    \"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"newline at start\",\n\t\t\tinput:    \"\\nhello\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:     \"other whitespace characters\",\n\t\t\tinput:    \"\\r\\nhello\",\n\t\t\texpected: \"\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult := whitespacePrefix(tt.input)\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n\nfunc TestUpdateShellConfig(t *testing.T) {\n\ttests := []struct {\n\t\tname           string\n\t\tshell          *Shell\n\t\tcontent        string\n\t\texpectedOutput string\n\t\texpectedUpdate bool\n\t}{\n\t\t{\n\t\t\tname: \"bash - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:        \"# Some existing config\\necho 'hello world'\\n\",\n\t\t\texpectedOutput: \"# Some existing config\\necho 'hello world'\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"bash - update existing initialization\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash --config theme.json\",\n\t\t\t},\n\t\t\tcontent:        \"# Some config\\neval \\\"$(oh-my-posh init bash)\\\"\\necho 'done'\\n\",\n\t\t\texpectedOutput: \"# Some config\\neval \\\"$(oh-my-posh init bash --config theme.json)\\\"\\necho 'done'\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"bash - no update when already correct\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:        \"# Some config\\neval \\\"$(oh-my-posh init bash)\\\"\\necho 'done'\\n\",\n\t\t\texpectedOutput: \"# Some config\\neval \\\"$(oh-my-posh init bash)\\\"\\necho 'done'\\n\",\n\t\t\texpectedUpdate: false,\n\t\t},\n\t\t{\n\t\t\tname: \"zsh - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"zsh\",\n\t\t\t\tCommand: \"oh-my-posh init zsh\",\n\t\t\t},\n\t\t\tcontent:        \"# ZSH config\\nexport PATH=$PATH:/usr/local/bin\\n\",\n\t\t\texpectedOutput: \"# ZSH config\\nexport PATH=$PATH:/usr/local/bin\\neval \\\"$(oh-my-posh init zsh)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"fish - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"fish\",\n\t\t\t\tCommand: \"oh-my-posh init fish\",\n\t\t\t},\n\t\t\tcontent:        \"# Fish config\\nset -x PATH $PATH /usr/local/bin\\n\",\n\t\t\texpectedOutput: \"# Fish config\\nset -x PATH $PATH /usr/local/bin\\noh-my-posh init fish | source\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"pwsh - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"pwsh\",\n\t\t\t\tCommand: \"oh-my-posh init pwsh\",\n\t\t\t},\n\t\t\tcontent:        \"# PowerShell config\\n$env:PATH += ';C:\\\\Program Files'\\n\",\n\t\t\texpectedOutput: \"# PowerShell config\\n$env:PATH += ';C:\\\\Program Files'\\noh-my-posh init pwsh | Invoke-Expression\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"elvish - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"elvish\",\n\t\t\t\tCommand: \"oh-my-posh init elvish\",\n\t\t\t},\n\t\t\tcontent:        \"# Elvish config\\nset paths = [$@paths /usr/local/bin]\\n\",\n\t\t\texpectedOutput: \"# Elvish config\\nset paths = [$@paths /usr/local/bin]\\neval (oh-my-posh init elvish)\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"xonsh - add initialization when not present\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"xonsh\",\n\t\t\t\tCommand: \"oh-my-posh init xonsh\",\n\t\t\t},\n\t\t\tcontent:        \"# Xonsh config\\n$PATH.append('/usr/local/bin')\\n\",\n\t\t\texpectedOutput: \"# Xonsh config\\n$PATH.append('/usr/local/bin')\\nexecx($(oh-my-posh init xonsh))\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"preserve indentation when updating\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash --config new.json\",\n\t\t\t},\n\t\t\tcontent:        \"if [ -f ~/.bashrc ]; then\\n    eval \\\"$(oh-my-posh init bash)\\\"\\nfi\\n\",\n\t\t\texpectedOutput: \"if [ -f ~/.bashrc ]; then\\n    eval \\\"$(oh-my-posh init bash --config new.json)\\\"\\nfi\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"ignore commented oh-my-posh lines\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:        \"# eval \\\"$(oh-my-posh init bash)\\\"\\necho 'commented out'\\n\",\n\t\t\texpectedOutput: \"# eval \\\"$(oh-my-posh init bash)\\\"\\necho 'commented out'\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"handle empty content\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:        \"\",\n\t\t\texpectedOutput: \"\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"handle content without trailing newline\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:        \"echo 'no newline'\",\n\t\t\texpectedOutput: \"echo 'no newline'\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"update oh-my-posh.exe reference\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash --config theme.json\",\n\t\t\t},\n\t\t\tcontent:        \"eval \\\"$(oh-my-posh.exe init bash)\\\"\\n\",\n\t\t\texpectedOutput: \"eval \\\"$(oh-my-posh init bash --config theme.json)\\\"\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t\t{\n\t\t\tname: \"mixed whitespace indentation preservation\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash --config theme.json\",\n\t\t\t},\n\t\t\tcontent:        \"if command -v oh-my-posh >/dev/null 2>&1; then\\n \\t  eval \\\"$(oh-my-posh init bash)\\\"\\nfi\\n\",\n\t\t\texpectedOutput: \"if command -v oh-my-posh >/dev/null 2>&1; then\\n \\t  eval \\\"$(oh-my-posh init bash --config theme.json)\\\"\\nfi\\n\",\n\t\t\texpectedUpdate: true,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult, updated := tt.shell.updateShellConfig(tt.content)\n\t\t\tassert.Equal(t, tt.expectedOutput, result)\n\t\t\tassert.Equal(t, tt.expectedUpdate, updated)\n\t\t})\n\t}\n}\n\nfunc TestGetInitLinePosition(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tlines    []string\n\t\texpected int\n\t}{\n\t\t{\n\t\t\tname: \"find oh-my-posh init line\",\n\t\t\tlines: []string{\n\t\t\t\t\"# Some config\",\n\t\t\t\t\"eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t\t\"echo 'done'\",\n\t\t\t},\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname: \"find oh-my-posh.exe init line\",\n\t\t\tlines: []string{\n\t\t\t\t\"# Some config\",\n\t\t\t\t\"oh-my-posh.exe init pwsh | Invoke-Expression\",\n\t\t\t\t\"echo 'done'\",\n\t\t\t},\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname: \"ignore commented lines\",\n\t\t\tlines: []string{\n\t\t\t\t\"# eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t\t\"echo 'test'\",\n\t\t\t\t\"eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t},\n\t\t\texpected: 2,\n\t\t},\n\t\t{\n\t\t\tname: \"ignore indented commented lines\",\n\t\t\tlines: []string{\n\t\t\t\t\"    # eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t\t\"eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t},\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname: \"no oh-my-posh init line found\",\n\t\t\tlines: []string{\n\t\t\t\t\"# Some config\",\n\t\t\t\t\"echo 'hello'\",\n\t\t\t\t\"export PATH=$PATH:/usr/local/bin\",\n\t\t\t},\n\t\t\texpected: -1,\n\t\t},\n\t\t{\n\t\t\tname: \"find last occurrence\",\n\t\t\tlines: []string{\n\t\t\t\t\"eval \\\"$(oh-my-posh init bash)\\\"\",\n\t\t\t\t\"# another line\",\n\t\t\t\t\"eval \\\"$(oh-my-posh init bash --config theme.json)\\\"\",\n\t\t\t},\n\t\t\texpected: 2,\n\t\t},\n\t\t{\n\t\t\tname: \"find with extra spaces\",\n\t\t\tlines: []string{\n\t\t\t\t\"# config\",\n\t\t\t\t\"oh-my-posh   init   fish | source\",\n\t\t\t},\n\t\t\texpected: 1,\n\t\t},\n\t\t{\n\t\t\tname:     \"empty lines array\",\n\t\t\tlines:    []string{},\n\t\t\texpected: -1,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tshell := &Shell{}\n\t\t\tresult := shell.getLastInitLinePosition(tt.lines)\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n\nfunc TestShellCommand(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tshell    *Shell\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"bash shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\texpected: `eval \"$(oh-my-posh init bash)\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"zsh shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"zsh\",\n\t\t\t\tCommand: \"oh-my-posh init zsh\",\n\t\t\t},\n\t\t\texpected: `eval \"$(oh-my-posh init zsh)\"`,\n\t\t},\n\t\t{\n\t\t\tname: \"fish shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"fish\",\n\t\t\t\tCommand: \"oh-my-posh init fish\",\n\t\t\t},\n\t\t\texpected: \"oh-my-posh init fish | source\",\n\t\t},\n\t\t{\n\t\t\tname: \"pwsh shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"pwsh\",\n\t\t\t\tCommand: \"oh-my-posh init pwsh\",\n\t\t\t},\n\t\t\texpected: \"oh-my-posh init pwsh | Invoke-Expression\",\n\t\t},\n\t\t{\n\t\t\tname: \"elvish shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"elvish\",\n\t\t\t\tCommand: \"oh-my-posh init elvish\",\n\t\t\t},\n\t\t\texpected: `eval (oh-my-posh init elvish)`,\n\t\t},\n\t\t{\n\t\t\tname: \"xonsh shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"xonsh\",\n\t\t\t\tCommand: \"oh-my-posh init xonsh\",\n\t\t\t},\n\t\t\texpected: `execx($(oh-my-posh init xonsh))`,\n\t\t},\n\t\t{\n\t\t\tname: \"unknown shell command\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"unknown\",\n\t\t\t\tCommand: \"oh-my-posh init unknown\",\n\t\t\t},\n\t\t\texpected: \"oh-my-posh init unknown\",\n\t\t},\n\t\t{\n\t\t\tname: \"bash with config\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash --config theme.json\",\n\t\t\t},\n\t\t\texpected: `eval \"$(oh-my-posh init bash --config theme.json)\"`,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult := tt.shell.shellCommand()\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n\nfunc TestAddInitLine(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tshell    *Shell\n\t\tcontent  string\n\t\texpected string\n\t}{\n\t\t{\n\t\t\tname: \"add to content with trailing newline\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:  \"# Some config\\necho 'hello'\\n\",\n\t\t\texpected: \"# Some config\\necho 'hello'\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"add to content without trailing newline\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:  \"# Some config\\necho 'hello'\",\n\t\t\texpected: \"# Some config\\necho 'hello'\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"add to empty content\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"bash\",\n\t\t\t\tCommand: \"oh-my-posh init bash\",\n\t\t\t},\n\t\t\tcontent:  \"\",\n\t\t\texpected: \"\\neval \\\"$(oh-my-posh init bash)\\\"\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"add fish init line\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"fish\",\n\t\t\t\tCommand: \"oh-my-posh init fish\",\n\t\t\t},\n\t\t\tcontent:  \"set -x PATH $PATH /usr/local/bin\\n\",\n\t\t\texpected: \"set -x PATH $PATH /usr/local/bin\\noh-my-posh init fish | source\\n\",\n\t\t},\n\t\t{\n\t\t\tname: \"add pwsh init line\",\n\t\t\tshell: &Shell{\n\t\t\t\tName:    \"pwsh\",\n\t\t\t\tCommand: \"oh-my-posh init pwsh\",\n\t\t\t},\n\t\t\tcontent:  \"$env:PATH += ';C:\\\\\\\\Program Files'\\n\",\n\t\t\texpected: \"$env:PATH += ';C:\\\\\\\\Program Files'\\noh-my-posh init pwsh | Invoke-Expression\\n\",\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tresult := tt.shell.addInitLine(tt.content)\n\t\t\tassert.Equal(t, tt.expected, result)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/shell/elvish.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n)\n\n//go:embed scripts/omp.elv\nvar elvishInit string\n\nfunc (f Features) Elvish() Code {\n\tswitch f {\n\tcase Upgrade:\n\t\treturn \"$_omp_executable upgrade --auto\"\n\tcase Notice:\n\t\treturn \"$_omp_executable notice\"\n\tcase PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, CursorPositioning, Tooltips, Transient, FTCSMarks, Async, Streaming, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "src/shell/elvish_test.go",
    "content": "package shell\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestElvishFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(ELVISH).String(\"// these are the features\")\n\n\twant := `// these are the features\n$_omp_executable upgrade --auto\n$_omp_executable notice`\n\n\tassert.Equal(t, want, got)\n}\n"
  },
  {
    "path": "src/shell/features.go",
    "content": "package shell\n\nimport \"fmt\"\n\ntype Features uint\n\nconst (\n\tJobs Features = 1 << iota\n\tAzure\n\tPoshGit\n\tLineError\n\tTooltips\n\tTransient\n\tFTCSMarks\n\tUpgrade\n\tNotice\n\tPromptMark\n\tRPrompt\n\tCursorPositioning\n\tAsync\n\tStreaming\n\tKeyHandlers\n)\n\n// getAllFeatures returns all defined feature flags by iterating through bit positions\nfunc getAllFeatures() []Features {\n\tvar features []Features\n\n\t// Iterate through all possible bit positions\n\tfor i := range uint(32) { // 32 should be more than enough for our features\n\t\tfeature := Features(1 << i)\n\n\t\t// Stop when we reach a power of 2 greater than our highest defined feature\n\t\tif feature > KeyHandlers*2 {\n\t\t\tbreak\n\t\t}\n\n\t\t// Add the feature if it's a power of 2 (valid feature flag)\n\t\tif feature != 0 && (feature&(feature-1)) == 0 {\n\t\t\tfeatures = append(features, feature)\n\t\t}\n\t}\n\n\treturn features\n}\n\nfunc (f Features) Lines(shell string) Lines {\n\tvar lines Lines\n\n\t// Get all features dynamically\n\tallFeatures := getAllFeatures()\n\n\tfor _, feature := range allFeatures {\n\t\t// Check if this feature is enabled in the Features bitmask\n\t\tif uint(f)&uint(feature) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tvar code Code\n\n\t\tswitch shell {\n\t\tcase PWSH:\n\t\t\tcode = feature.Pwsh()\n\t\tcase ZSH:\n\t\t\tcode = feature.Zsh()\n\t\tcase BASH:\n\t\t\tcode = feature.Bash()\n\t\tcase ELVISH:\n\t\t\tcode = feature.Elvish()\n\t\tcase FISH:\n\t\t\tcode = feature.Fish()\n\t\tcase CMD:\n\t\t\tcode = feature.Cmd()\n\t\tcase NU:\n\t\t\tcode = feature.Nu()\n\t\tcase XONSH:\n\t\t\tcode = feature.Xonsh()\n\t\t}\n\n\t\tif len(code) > 0 {\n\t\t\tlines = append(lines, code)\n\t\t}\n\t}\n\n\treturn lines\n}\n\nfunc (f Features) String() string {\n\treturn fmt.Sprintf(\"%b\", uint(f))\n}\n"
  },
  {
    "path": "src/shell/filesystem.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"hash/fnv\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nvar scriptPathCache string\n\nfunc hasScript(env runtime.Environment) (string, bool) {\n\tif env.Flags().Debug || env.Flags().Eval || env.Flags().Shell == NU {\n\t\tlog.Debug(\"in debug or eval mode, no script path will be used\")\n\t\treturn \"\", false\n\t}\n\n\tpath, err := scriptPath(env)\n\tif err != nil {\n\t\tlog.Debug(\"failed to get script path\")\n\t\treturn \"\", false\n\t}\n\n\t_, err = os.Stat(path)\n\tif err != nil {\n\t\tlog.Debug(\"script path does not exist\")\n\t\treturn \"\", false\n\t}\n\n\t// check if we have the same context\n\tif val, _ := cache.Get[string](cache.Device, cacheKey(env.Flags().Shell)); val != cacheValue(env) {\n\t\tlog.Debug(\"script context has changed\")\n\t\treturn \"\", false\n\t}\n\n\tlog.Debug(\"script context is unchanged\")\n\treturn path, true\n}\n\nfunc writeScript(env runtime.Environment, script string) (string, error) {\n\tpath, err := scriptPath(env)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\terr = os.WriteFile(path, []byte(script), 0o644)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\n\tlog.Debug(\"init script written successfully\")\n\tcache.Set(cache.Device, cacheKey(env.Flags().Shell), cacheValue(env), cache.INFINITE)\n\n\treturn path, nil\n}\n\nfunc cacheKey(sh string) string {\n\treturn fmt.Sprintf(\"INITVERSION%s\", strings.ToUpper(sh))\n}\n\nfunc cacheValue(env runtime.Environment) string {\n\treturn fmt.Sprintf(\"%d%s\", env.Flags().ConfigHash, build.Version)\n}\n\nfunc InitScriptName(flags *runtime.Flags) string {\n\tsh := flags.Shell\n\tswitch flags.Shell {\n\tcase PWSH:\n\t\tsh = \"ps1\"\n\tcase CMD:\n\t\tsh = \"lua\"\n\tcase BASH:\n\t\tsh = \"sh\"\n\tcase ELVISH:\n\t\tsh = \"elv\"\n\tcase XONSH:\n\t\tsh = \"xsh\"\n\t}\n\n\t// to avoid a single init scripts for different configs\n\t// we hash the config path as part of the script name\n\t// that way we have a single init script per config\n\t// avoiding conflicts\n\th := fnv.New64a()\n\th.Write([]byte(flags.ConfigPath))\n\thash := h.Sum64()\n\n\treturn fmt.Sprintf(\"init.%d.%s\", hash, sh)\n}\n\nfunc scriptPath(env runtime.Environment) (string, error) {\n\tif len(scriptPathCache) != 0 {\n\t\treturn scriptPathCache, nil\n\t}\n\n\tif env.Flags().Shell != NU {\n\t\tscriptPathCache = filepath.Join(cache.Path(), InitScriptName(env.Flags()))\n\t\tlog.Debug(\"init script path for non-nu shell:\", scriptPathCache)\n\t\treturn scriptPathCache, nil\n\t}\n\n\tconst autoloadDir = \"NUAUTOLOADDIR\"\n\tconst fileName = \"oh-my-posh.nu\"\n\n\tif dir, OK := cache.Get[string](cache.Device, autoloadDir); OK {\n\t\tscriptPathCache = filepath.Join(dir, fileName)\n\t\tlog.Debug(\"autoload path for nu from cache:\", dir)\n\t\treturn scriptPathCache, nil\n\t}\n\n\tautoloadPath, err := env.RunCommand(\"nu\", \"-c\", \"$nu.data-dir | path join vendor autoload\")\n\tif err != nil || autoloadPath == \"\" {\n\t\tlog.Error(err)\n\t\treturn \"\", err\n\t}\n\n\tlog.Debug(\"autoload path for nu:\", autoloadPath)\n\n\t// create the path if non-existent\n\t_, err = os.Stat(autoloadPath)\n\tif err != nil {\n\t\tlog.Debug(\"autoload path does not exist, creating\")\n\t\terr = os.MkdirAll(autoloadPath, 0o700)\n\t}\n\n\tif err != nil {\n\t\tlog.Debugf(\"failed to create autoload dir %s: %s\", autoloadPath, err)\n\t\treturn \"\", err\n\t}\n\n\tcache.Set(cache.Device, autoloadDir, autoloadPath, cache.INFINITE)\n\tscriptPathCache = filepath.Join(autoloadPath, fileName)\n\tlog.Debug(\"script path for nu:\", scriptPathCache)\n\treturn scriptPathCache, nil\n}\n"
  },
  {
    "path": "src/shell/fish.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.fish\nvar fishInit string\n\nfunc (f Features) Fish() Code {\n\tswitch f {\n\tcase Transient:\n\t\treturn \"set --global _omp_transient_prompt 1\"\n\tcase FTCSMarks:\n\t\treturn \"set --global _omp_ftcs_marks 1\"\n\tcase PromptMark:\n\t\treturn \"set --global _omp_prompt_mark 1\"\n\tcase Tooltips:\n\t\treturn \"enable_poshtooltips\"\n\tcase Streaming:\n\t\treturn \"set --global _omp_enable_streaming 1\"\n\tcase Upgrade:\n\t\treturn unixUpgrade\n\tcase Notice:\n\t\treturn unixNotice\n\tcase RPrompt, PoshGit, Azure, LineError, Jobs, CursorPositioning, Async, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc quoteFishStr(str string) string {\n\tif str == \"\" {\n\t\treturn \"''\"\n\t}\n\n\treturn fmt.Sprintf(\"'%s'\", strings.NewReplacer(`\\`, `\\\\`, \"'\", `\\'`).Replace(str))\n}\n"
  },
  {
    "path": "src/shell/fish_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFishFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(FISH).String(\"// these are the features\")\n\n\twant := `// these are the features\nenable_poshtooltips\nset --global _omp_transient_prompt 1\nset --global _omp_ftcs_marks 1\n\"$_omp_executable\" upgrade --auto\n\"$_omp_executable\" notice\nset --global _omp_prompt_mark 1\nset --global _omp_enable_streaming 1`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestQuoteFishStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"''\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `'/tmp/\"omp\\'s dir\"/oh-my-posh'`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\\\\omp\\'s dir/oh-my-posh.exe'`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, quoteFishStr(tc.str), fmt.Sprintf(\"quoteFishStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/formats.go",
    "content": "package shell\n\ntype Formats struct {\n\tEscape     string\n\tLeft       string\n\tLinechange string\n\tClearBelow string\n\tClearLine  string\n\n\tTitle string\n\n\tSaveCursorPosition    string\n\tRestoreCursorPosition string\n\n\tOsc99 string\n\tOsc7  string\n\tOsc51 string\n\n\tEscapeSequences map[rune]string\n\n\tHyperlinkStart  string\n\tHyperlinkCenter string\n\tHyperlinkEnd    string\n\n\tITermPromptMark string\n\tITermCurrentDir string\n\tITermRemoteHost string\n}\n\nfunc GetFormats(shell string) *Formats {\n\tvar formats *Formats\n\n\tswitch shell {\n\tcase BASH:\n\t\tformats = &Formats{\n\t\t\tEscape:                \"\\\\[%s\\\\]\",\n\t\t\tLinechange:            \"\\\\[\\x1b[%d%s\\\\]\",\n\t\t\tLeft:                  \"\\\\[\\x1b[%dD\\\\]\",\n\t\t\tClearBelow:            \"\\\\[\\x1b[0J\\\\]\",\n\t\t\tClearLine:             \"\\\\[\\x1b[K\\\\]\",\n\t\t\tSaveCursorPosition:    \"\\\\[\\x1b7\\\\]\",\n\t\t\tRestoreCursorPosition: \"\\\\[\\x1b8\\\\]\",\n\t\t\tTitle:                 \"\\\\[\\x1b]0;%s\\007\\\\]\",\n\t\t\tHyperlinkStart:        \"\\\\[\\x1b]8;;\",\n\t\t\tHyperlinkCenter:       \"\\x1b\\\\\\\\\\\\]\",\n\t\t\tHyperlinkEnd:          \"\\\\[\\x1b]8;;\\x1b\\\\\\\\\\\\]\",\n\t\t\tOsc99:                 \"\\\\[\\x1b]9;9;%s\\x1b\\\\\\\\\\\\]\",\n\t\t\tOsc7:                  \"\\\\[\\x1b]7;file://%s/%s\\x1b\\\\\\\\\\\\]\",\n\t\t\tOsc51:                 \"\\\\[\\x1b]51;A;%s@%s:%s\\x1b\\\\\\\\\\\\]\",\n\t\t\tITermPromptMark:       \"\\\\[$(iterm2_prompt_mark)\\\\]\",\n\t\t\tITermCurrentDir:       \"\\\\[\\x1b]1337;CurrentDir=%s\\x07\\\\]\",\n\t\t\tITermRemoteHost:       \"\\\\[\\x1b]1337;RemoteHost=%s@%s\\x07\\\\]\",\n\t\t\tEscapeSequences: map[rune]string{\n\t\t\t\t'\\\\': `\\\\`,\n\t\t\t},\n\t\t}\n\tcase ZSH:\n\t\tformats = &Formats{\n\t\t\tEscape:                \"%%{%s%%}\",\n\t\t\tLinechange:            \"%%{\\x1b[%d%s%%}\",\n\t\t\tLeft:                  \"%%{\\x1b[%dD%%}\",\n\t\t\tClearBelow:            \"%{\\x1b[0J%}\",\n\t\t\tClearLine:             \"%{\\x1b[K%}\",\n\t\t\tSaveCursorPosition:    \"%{\\x1b7%}\",\n\t\t\tRestoreCursorPosition: \"%{\\x1b8%}\",\n\t\t\tTitle:                 \"%%{\\x1b]0;%s\\007%%}\",\n\t\t\tHyperlinkStart:        \"%{\\x1b]8;;\",\n\t\t\tHyperlinkCenter:       \"\\x1b\\\\%}\",\n\t\t\tHyperlinkEnd:          \"%{\\x1b]8;;\\x1b\\\\%}\",\n\t\t\tOsc99:                 \"%%{\\x1b]9;9;%s\\x1b\\\\%%}\",\n\t\t\tOsc7:                  \"%%{\\x1b]7;file://%s/%s\\x1b\\\\%%}\",\n\t\t\tOsc51:                 \"%%{\\x1b]51;A%s@%s:%s\\x1b\\\\%%}\",\n\t\t\tITermPromptMark:       \"%{$(iterm2_prompt_mark)%}\",\n\t\t\tITermCurrentDir:       \"%%{\\x1b]1337;CurrentDir=%s\\x07%%}\",\n\t\t\tITermRemoteHost:       \"%%{\\x1b]1337;RemoteHost=%s@%s\\x07%%}\",\n\t\t\tEscapeSequences: map[rune]string{\n\t\t\t\t'%': \"%%\",\n\t\t\t},\n\t\t}\n\tdefault:\n\t\tformats = &Formats{\n\t\t\tEscape:                \"%s\",\n\t\t\tLinechange:            \"\\x1b[%d%s\",\n\t\t\tLeft:                  \"\\x1b[%dD\",\n\t\t\tClearBelow:            \"\\x1b[0J\",\n\t\t\tClearLine:             \"\\x1b[K\",\n\t\t\tSaveCursorPosition:    \"\\x1b7\",\n\t\t\tRestoreCursorPosition: \"\\x1b8\",\n\t\t\tTitle:                 \"\\x1b]0;%s\\007\",\n\t\t\t// when in fish on Linux, it seems hyperlinks ending with \\\\ print a \\\n\t\t\t// unlike on macOS. However, this is a fish bug, so do not try to fix it here:\n\t\t\t// https://github.com/JanDeDobbeleer/oh-my-posh/pull/3288#issuecomment-1369137068\n\t\t\tHyperlinkStart:  \"\\x1b]8;;\",\n\t\t\tHyperlinkCenter: \"\\x1b\\\\\",\n\t\t\tHyperlinkEnd:    \"\\x1b]8;;\\x1b\\\\\",\n\t\t\tOsc99:           \"\\x1b]9;9;%s\\x1b\\\\\",\n\t\t\tOsc7:            \"\\x1b]7;file://%s/%s\\x1b\\\\\",\n\t\t\tOsc51:           \"\\x1b]51;A%s@%s:%s\\x1b\\\\\",\n\t\t\tITermCurrentDir: \"\\x1b]1337;CurrentDir=%s\\x07\",\n\t\t\tITermRemoteHost: \"\\x1b]1337;RemoteHost=%s@%s\\x07\",\n\t\t}\n\t}\n\n\treturn formats\n}\n"
  },
  {
    "path": "src/shell/init.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nconst (\n\tnoExe = \"echo \\\"Unable to find Oh My Posh executable\\\"\"\n)\n\nvar (\n\t// identify ble.sh by validating the existence of BLE_SESSION_ID\n\tbashBLEsession bool\n)\n\nfunc getExecutablePath(env runtime.Environment) (string, error) {\n\texecutable, err := os.Executable()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t_, msix := cache.PackageFamilyName()\n\tif msix || env.Flags().Strict {\n\t\treturn path.Base(executable), nil\n\t}\n\n\t// On Windows, it fails when the executable is called in MSYS2 for example\n\t// which uses unix style paths to resolve the executable's location.\n\t// PowerShell knows how to resolve both, so we can swap this without any issue.\n\tif env.GOOS() == runtime.WINDOWS {\n\t\texecutable = strings.ReplaceAll(executable, \"\\\\\", \"/\")\n\t}\n\n\treturn executable, nil\n}\n\n// Init returns the command to initialize oh-my-posh for the shell.\n// It writes the init script to the appropriate location and returns\n// a source command or wrapper command depending on the shell.\n// For Nu shell, it writes to the autoload directory and returns empty.\n// For PWSH/Elvish, it returns a wrapper command that re-invokes oh-my-posh.\nfunc Init(env runtime.Environment, feats Features) string {\n\tswitch env.Flags().Shell {\n\tcase PWSH:\n\t\tif !env.Flags().Eval {\n\t\t\treturn generateAndSourceScript(env, feats)\n\t\t}\n\n\t\treturn recurseInitCommand(env)\n\tcase ELVISH:\n\t\treturn recurseInitCommand(env)\n\tcase NU:\n\t\treturn initNu(env, feats)\n\tcase ZSH, BASH, FISH, CMD, XONSH:\n\t\treturn generateAndSourceScript(env, feats)\n\tdefault:\n\t\treturn fmt.Sprintf(`echo \"%s is not supported by Oh My Posh\"`, env.Flags().Shell)\n\t}\n}\n\n// Script returns the init script content directly.\n// This is used by the --print flag to output the script to stdout.\nfunc Script(env runtime.Environment, feats Features) string {\n\tscript := generateScript(env, feats)\n\treturn fmt.Sprintf(\"%s\\n%s\", sessionScript(env.Flags().Shell), script)\n}\n\n// Debug writes the init script and returns debug information.\n// This is used by the --debug flag.\nfunc Debug(env runtime.Environment, feats Features, startTime *time.Time) string {\n\tscript := generateScript(env, feats)\n\n\tlog.Debug(script)\n\n\tif _, err := writeScript(env, script); err != nil {\n\t\tlog.Error(err)\n\t}\n\n\treturn printDebugInfo(env, startTime)\n}\n\n// recurseInitCommand returns a wrapper command that re-invokes oh-my-posh\n// with --print. This is used by PWSH and Elvish which eval the script.\nfunc recurseInitCommand(env runtime.Environment) string {\n\texecutable, err := getExecutablePath(env)\n\tif err != nil {\n\t\treturn noExe\n\t}\n\n\tvar additionalParams string\n\n\tif env.Flags().Strict {\n\t\tadditionalParams += \" --strict\"\n\t}\n\n\tif env.Flags().Eval {\n\t\tadditionalParams += \" --eval\"\n\t}\n\n\tconfig := quotePwshOrElvishStr(env.Flags().ConfigPath)\n\texecutable = quotePwshOrElvishStr(executable)\n\n\tvar command string\n\n\tswitch env.Flags().Shell {\n\tcase PWSH:\n\t\tcommand = \"(@(& %s init %s --config=%s --print%s) -join \\\"`n\\\") | Invoke-Expression\"\n\tcase ELVISH:\n\t\tcommand = \"eval ((external %s) init %s --config=%s --print%s | slurp)\"\n\t}\n\n\treturn fmt.Sprintf(command, executable, env.Flags().Shell, config, additionalParams)\n}\n\n// generateAndSourceScript writes the init script to the cache and returns a source command.\nfunc generateAndSourceScript(env runtime.Environment, feats Features) string {\n\tasync := feats&Async != 0\n\n\tif scriptPath, ok := hasScript(env); ok {\n\t\treturn sourceCommand(env, scriptPath, async)\n\t}\n\n\tscript := generateScript(env, feats)\n\n\tlog.Debug(script)\n\n\tscriptPath, err := writeScript(env, script)\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"echo \\\"Failed to write init script: %s\\\"\", err.Error())\n\t}\n\n\treturn sourceCommand(env, scriptPath, async)\n}\n\n// initNu writes the init script to Nu's autoload directory.\n// It returns empty since Nu automatically loads from the autoload directory.\nfunc initNu(env runtime.Environment, feats Features) string {\n\tscript := generateNuScript(env, feats)\n\n\tscriptPath, err := writeScript(env, script)\n\tif err != nil {\n\t\treturn fmt.Sprintf(\"echo \\\"Failed to write init script: %s\\\"\", err.Error())\n\t}\n\n\tlog.Debug(\"nu init script written to:\", scriptPath)\n\n\treturn \"\"\n}\n\n// generateScript generates the init script content for the current shell.\nfunc generateScript(env runtime.Environment, feats Features) string {\n\texecutable, err := getExecutablePath(env)\n\tif err != nil {\n\t\treturn noExe\n\t}\n\n\tbashBLEsession = len(env.Getenv(\"BLE_SESSION_ID\")) != 0\n\n\tvar script string\n\n\tswitch env.Flags().Shell {\n\tcase PWSH:\n\t\texecutable = quotePwshOrElvishStr(executable)\n\t\tscript = pwshInit\n\tcase ZSH:\n\t\texecutable = QuotePosixStr(executable)\n\t\tscript = zshInit\n\tcase BASH:\n\t\texecutable = QuotePosixStr(executable)\n\t\tscript = bashInit\n\tcase FISH:\n\t\texecutable = quoteFishStr(executable)\n\t\tscript = fishInit\n\tcase CMD:\n\t\texecutable = escapeLuaStr(executable)\n\t\tscript = cmdInit\n\tcase NU:\n\t\texecutable = quoteNuStr(executable)\n\t\tscript = nuInit\n\tcase ELVISH:\n\t\texecutable = quotePwshOrElvishStr(executable)\n\t\tscript = elvishInit\n\tcase XONSH:\n\t\texecutable = quotePythonStr(executable)\n\t\tscript = xonshInit\n\tdefault:\n\t\treturn fmt.Sprintf(\"echo \\\"No initialization script available for %s\\\"\", env.Flags().Shell)\n\t}\n\n\t// Remove UTF-8 BOM if present, as it can cause issues in some shells.\n\tscript = strings.TrimPrefix(script, \"\\xef\\xbb\\xbf\")\n\n\tinit := strings.NewReplacer(\n\t\t\"::OMP::\", executable,\n\t\t\"::SESSION_ID::\", cache.SessionID(),\n\t).Replace(script)\n\n\treturn feats.Lines(env.Flags().Shell).String(init)\n}\n\n// generateNuScript generates the init script content specifically for Nu shell.\nfunc generateNuScript(env runtime.Environment, feats Features) string {\n\texecutable, err := getExecutablePath(env)\n\tif err != nil {\n\t\treturn noExe\n\t}\n\n\texecutable = quoteNuStr(executable)\n\n\tinit := strings.NewReplacer(\n\t\t\"::OMP::\", executable,\n\t\t\"::SESSION_ID::\", cache.SessionID(),\n\t).Replace(nuInit)\n\n\treturn feats.Lines(NU).String(init)\n}\n\n// sourceCommand returns the command to source the init script.\nfunc sourceCommand(env runtime.Environment, scriptPath string, async bool) string {\n\tif env.IsCygwin() {\n\t\tvar err error\n\t\tscriptPath, err = env.RunCommand(\"cygpath\", \"-u\", scriptPath)\n\t\tif err != nil {\n\t\t\tlog.Error(err)\n\t\t\treturn fmt.Sprintf(\"echo \\\"Failed to convert Cygwin path due to %s\\\"\", err.Error())\n\t\t}\n\t}\n\n\tscript := sessionScript(env.Flags().Shell)\n\n\tif async {\n\t\treturn script + sourceCommandAsync(env.Flags().Shell, scriptPath)\n\t}\n\n\tswitch env.Flags().Shell {\n\tcase PWSH:\n\t\tscript += fmt.Sprintf(\"& %s\", quotePwshOrElvishStr(scriptPath))\n\tcase ZSH, BASH:\n\t\tscript += fmt.Sprintf(\"source %s\", QuotePosixStr(scriptPath))\n\tcase XONSH:\n\t\tscript += fmt.Sprintf(\"source %s\", quotePythonStr(scriptPath))\n\tcase FISH:\n\t\tscript += fmt.Sprintf(\"source %s\", quoteFishStr(scriptPath))\n\tcase ELVISH:\n\t\tscript += fmt.Sprintf(\"eval (slurp < %s)\", quotePwshOrElvishStr(scriptPath))\n\tcase CMD:\n\t\tscript += fmt.Sprintf(`load(io.open('%s', \"r\"):read(\"*a\"))()`, escapeLuaStr(scriptPath))\n\tdefault:\n\t\treturn fmt.Sprintf(\"echo \\\"No source command available for %s\\\"\", env.Flags().Shell)\n\t}\n\n\treturn script\n}\n\n// sourceCommandAsync returns the async source command for supported shells.\nfunc sourceCommandAsync(shell, scriptPath string) string {\n\tswitch shell {\n\tcase PWSH:\n\t\treturn fmt.Sprintf(\"function prompt() { & %s }\", quotePwshOrElvishStr(scriptPath))\n\tcase ZSH:\n\t\treturn fmt.Sprintf(\"precmd() { source %s }\", QuotePosixStr(scriptPath))\n\tcase BASH:\n\t\tcommand := fmt.Sprintf(\"source %s\", QuotePosixStr(scriptPath))\n\t\treturn fmt.Sprintf(\"PROMPT_COMMAND=%s\", QuotePosixStr(command))\n\tcase FISH:\n\t\treturn fmt.Sprintf(\"function fish_prompt; source %s; end\", quoteFishStr(scriptPath))\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc printDebugInfo(env runtime.Environment, startTime *time.Time) string {\n\tbuilder := text.NewBuilder()\n\n\tbuilder.WriteString(fmt.Sprintf(\"\\n%s %s\\n\", log.Text(\"Init duration:\").Green().Bold().Plain(), time.Since(*startTime)))\n\n\tbuilder.WriteString(log.Text(\"\\n\\nLogs:\\n\\n\").Green().Bold().Plain().String())\n\tbuilder.WriteString(env.Logs())\n\n\treturn builder.String()\n}\n\nfunc sessionScript(shell string) string {\n\tswitch shell {\n\tcase PWSH:\n\t\treturn fmt.Sprintf(\"$env:POSH_SESSION_ID = \\\"%s\\\";\", cache.SessionID())\n\tcase ZSH, BASH:\n\t\treturn fmt.Sprintf(\"export POSH_SESSION_ID=\\\"%s\\\";\", cache.SessionID())\n\tcase XONSH:\n\t\treturn fmt.Sprintf(\"$POSH_SESSION_ID = \\\"%s\\\";\", cache.SessionID())\n\tcase FISH:\n\t\treturn fmt.Sprintf(\"set --export --global POSH_SESSION_ID \\\"%s\\\";\", cache.SessionID())\n\tcase ELVISH:\n\t\treturn fmt.Sprintf(\"set-env POSH_SESSION_ID \\\"%s\\\";\", cache.SessionID())\n\tcase CMD:\n\t\treturn fmt.Sprintf(`os.setenv('POSH_SESSION_ID', '%s');`, cache.SessionID())\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "src/shell/nu.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.nu\nvar nuInit string\n\nfunc (f Features) Nu() Code {\n\tswitch f {\n\tcase Transient:\n\t\treturn `$env.TRANSIENT_PROMPT_COMMAND = {|| _omp_get_prompt transient }`\n\tcase Upgrade:\n\t\treturn \"^$_omp_executable upgrade --auto\"\n\tcase Notice:\n\t\treturn \"^$_omp_executable notice\"\n\tcase PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, FTCSMarks, CursorPositioning, Async, Streaming, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc quoteNuStr(str string) string {\n\tif str == \"\" {\n\t\treturn \"''\"\n\t}\n\n\treturn fmt.Sprintf(`\"%s\"`, strings.NewReplacer(`\\`, `\\\\`, `\"`, `\\\"`).Replace(str))\n}\n"
  },
  {
    "path": "src/shell/nu_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestNuFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(NU).String(\"// these are the features\")\n\n\twant := `// these are the features\n$env.TRANSIENT_PROMPT_COMMAND = {|| _omp_get_prompt transient }\n^$_omp_executable upgrade --auto\n^$_omp_executable notice`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestQuoteNuStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"''\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `\"/tmp/\\\"omp's dir\\\"/oh-my-posh\"`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `\"C:/tmp\\\\omp's dir/oh-my-posh.exe\"`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, quoteNuStr(tc.str), fmt.Sprintf(\"quoteNuStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/pwsh.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.ps1\nvar pwshInit string\n\nfunc (f Features) Pwsh() Code {\n\tswitch f {\n\tcase Tooltips:\n\t\treturn \"Enable-PoshTooltips\"\n\tcase LineError:\n\t\treturn \"Enable-PoshLineError\"\n\tcase Transient:\n\t\treturn \"$global:_ompTransientPrompt = $true\"\n\tcase Jobs:\n\t\treturn \"$global:_ompJobCount = $true\"\n\tcase Azure:\n\t\treturn \"$global:_ompAzure = $true\"\n\tcase PoshGit:\n\t\treturn \"$global:_ompPoshGit = $true\"\n\tcase FTCSMarks:\n\t\treturn \"$global:_ompFTCSMarks = $true\"\n\tcase Upgrade:\n\t\treturn \"& $global:_ompExecutable upgrade --auto\"\n\tcase Notice:\n\t\treturn \"& $global:_ompExecutable notice\"\n\tcase Streaming:\n\t\treturn \"$global:_ompStreaming = $true\"\n\tcase KeyHandlers:\n\t\treturn \"Enable-KeyHandlers\"\n\tcase PromptMark, RPrompt, CursorPositioning, Async:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc quotePwshOrElvishStr(str string) string {\n\tif str == \"\" {\n\t\treturn \"''\"\n\t}\n\n\treturn fmt.Sprintf(\"'%s'\", strings.ReplaceAll(str, \"'\", \"''\"))\n}\n"
  },
  {
    "path": "src/shell/pwsh_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar allFeatures = Tooltips | LineError | Transient | Jobs | Azure | PoshGit | FTCSMarks | Upgrade | Notice | PromptMark | RPrompt | CursorPositioning | KeyHandlers | Streaming\n\nfunc TestPwshFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(PWSH).String(\"\")\n\n\twant := `\n$global:_ompJobCount = $true\n$global:_ompAzure = $true\n$global:_ompPoshGit = $true\nEnable-PoshLineError\nEnable-PoshTooltips\n$global:_ompTransientPrompt = $true\n$global:_ompFTCSMarks = $true\n& $global:_ompExecutable upgrade --auto\n& $global:_ompExecutable notice\n$global:_ompStreaming = $true\nEnable-KeyHandlers`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestQuotePwshOrElvishStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"''\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `'/tmp/\"omp''s dir\"/oh-my-posh'`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\\omp''s dir/oh-my-posh.exe'`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, quotePwshOrElvishStr(tc.str), fmt.Sprintf(\"quotePwshOrElvishStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/scripts/omp.bash",
    "content": "export POSH_SHELL='bash'\nexport POSH_SHELL_VERSION=$BASH_VERSION\nexport POWERLINE_COMMAND='oh-my-posh'\nexport CONDA_PROMPT_MODIFIER=false\nexport OSTYPE=$OSTYPE\n\n# disable all known python virtual environment prompts\nexport VIRTUAL_ENV_DISABLE_PROMPT=1\nexport PYENV_VIRTUALENV_DISABLE_PROMPT=1\n\n# global variables\n_omp_start_time=''\n_omp_stack_count=0\n_omp_execution_time=-1\n_omp_no_status=true\n_omp_status=0\n_omp_pipestatus=0\n_omp_executable=::OMP::\n\n# switches to enable/disable features\n_omp_cursor_positioning=0\n_omp_ftcs_marks=0\n\n# start timer on command start\nPS0='${_omp_start_time:0:$((_omp_start_time=\"$(_omp_start_timer)\",0))}$(_omp_ftcs_command_start)'\n\n# set secondary prompt\n_omp_secondary_prompt=$(\n    \"$_omp_executable\" print secondary \\\n        --shell=bash \\\n        --shell-version=\"$BASH_VERSION\"\n)\n\nfunction _omp_set_cursor_position() {\n    # not supported in Midnight Commander\n    # see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415\n    if [[ $_omp_cursor_positioning == 0 ]] || [[ -v MC_SID ]]; then\n        return\n    fi\n\n    local oldstty=$(stty -g)\n    stty raw -echo min 0\n\n    local COL\n    local ROW\n    IFS=';' read -rsdR -p $'\\E[6n' ROW COL\n\n    stty \"$oldstty\"\n\n    export POSH_CURSOR_LINE=${ROW#*[}\n    export POSH_CURSOR_COLUMN=${COL}\n}\n\nfunction _omp_start_timer() {\n    \"$_omp_executable\" get millis\n}\n\nfunction _omp_ftcs_command_start() {\n    if [[ $_omp_ftcs_marks == 1 ]]; then\n        printf '\\e]133;C\\a'\n    fi\n}\n\n# template function for context loading\nfunction set_poshcontext() {\n    return\n}\n\nfunction _omp_get_primary() {\n    # Avoid unexpected expansions when we're generating the prompt below.\n    shopt -u promptvars\n    trap 'shopt -s promptvars' RETURN\n\n    local prompt\n    if shopt -oq posix; then\n        # Disable in POSIX mode.\n        prompt='[NOTICE: Oh My Posh prompt is not supported in POSIX mode]\\n\\u@\\h:\\w\\$ '\n    else\n        prompt=$(\n            \"$_omp_executable\" print primary \\\n                --save-cache \\\n                --shell=bash \\\n                --shell-version=\"$BASH_VERSION\" \\\n                --status=\"$_omp_status\" \\\n                --pipestatus=\"${_omp_pipestatus[*]}\" \\\n                --no-status=\"$_omp_no_status\" \\\n                --execution-time=\"$_omp_execution_time\" \\\n                --stack-count=\"$_omp_stack_count\" \\\n                --terminal-width=\"${COLUMNS-0}\" |\n                tr -d '\\0'\n        )\n    fi\n    echo \"${prompt@P}\"\n}\n\nfunction _omp_get_secondary() {\n    # Avoid unexpected expansions when we're generating the prompt below.\n    shopt -u promptvars\n    trap 'shopt -s promptvars' RETURN\n\n    if shopt -oq posix; then\n        # Disable in POSIX mode.\n        echo '> '\n    else\n        echo \"${_omp_secondary_prompt@P}\"\n    fi\n}\n\nfunction _omp_hook() {\n    _omp_status=$? _omp_pipestatus=(\"${PIPESTATUS[@]}\")\n\n    if [[ -v BP_PIPESTATUS && ${#BP_PIPESTATUS[@]} -ge ${#_omp_pipestatus[@]} ]]; then\n        _omp_pipestatus=(\"${BP_PIPESTATUS[@]}\")\n    fi\n\n    _omp_stack_count=$((${#DIRSTACK[@]} - 1))\n\n    _omp_execution_time=-1\n    if [[ $_omp_start_time ]]; then\n        local omp_now=$(\"$_omp_executable\" get millis)\n        _omp_execution_time=$((omp_now - _omp_start_time))\n        _omp_no_status=false\n    fi\n    _omp_start_time=''\n\n    if [[ ${_omp_pipestatus[-1]} != \"$_omp_status\" ]]; then\n        _omp_pipestatus=(\"$_omp_status\")\n    fi\n\n    set_poshcontext\n    _omp_set_cursor_position\n\n    PS1='$(_omp_get_primary)'\n    PS2='$(_omp_get_secondary)'\n\n    # Ensure that command substitution works in a prompt string.\n    shopt -s promptvars\n\n    return $_omp_status\n}\n\nfunction _omp_install_hook() {\n    local cmd\n    local prompt_command\n\n    for cmd in \"${PROMPT_COMMAND[@]}\"; do\n        # skip initializing when we're already initialized\n        if [[ $cmd = _omp_hook ]]; then\n            return\n        fi\n\n        # check if the command starts with source, if so, do not add it again\n        # this is done to avoid issues with sourcing the same file multiple times\n        if [[ $cmd = source* ]]; then\n            continue\n        fi\n\n        prompt_command+=(\"$cmd\")\n    done\n\n    PROMPT_COMMAND=(\"${prompt_command[@]}\" _omp_hook)\n}\n\n_omp_install_hook\n"
  },
  {
    "path": "src/shell/scripts/omp.elv",
    "content": "set-env POSH_SHELL elvish\nset-env POSH_SHELL_VERSION $version\nset-env POWERLINE_COMMAND oh-my-posh\n\n# disable all known python virtual environment prompts\nset-env VIRTUAL_ENV_DISABLE_PROMPT 1\nset-env PYENV_VIRTUALENV_DISABLE_PROMPT 1\n\nvar _omp_executable = (external ::OMP::)\nvar _omp_status = 0\nvar _omp_no_status = 1\nvar _omp_execution_time = -1\nvar _omp_terminal_width = ($_omp_executable get width)\n\n# A flag to simulate a mutex.\nvar _omp_primary_ready = $false\n\nfn _omp-after-readline-hook {|_|\n    set _omp_execution_time = -1\n\n    # Getting the terminal width can fail inside a prompt function, so we do this here.\n    set _omp_terminal_width = ($_omp_executable get width)\n}\n\nfn _omp-after-command-hook {|m|\n    # The command execution time should not be available in the first prompt.\n    if (== $_omp_no_status 0) {\n        set _omp_execution_time = (printf %.0f (* $m[duration] 1000))\n    }\n\n    set _omp_no_status = 0\n\n    var error = $m[error]\n    if (is $error $nil) {\n        set _omp_status = 0\n    } else {\n        try {\n            set _omp_status = $error[reason][exit-status]\n        } catch {\n            # built-in commands don't have a status code.\n            set _omp_status = 1\n        }\n    }\n}\n\nfn _omp_get_prompt {|type @arguments|\n    $_omp_executable print $type ^\n        --save-cache ^\n        --shell=elvish ^\n        --shell-version=$E:POSH_SHELL_VERSION ^\n        --status=$_omp_status ^\n        --no-status=$_omp_no_status ^\n        --execution-time=$_omp_execution_time ^\n        --terminal-width=$_omp_terminal_width ^\n        $@arguments\n}\n\nset edit:after-readline = [ $@edit:after-readline $_omp-after-readline-hook~ ]\nset edit:after-command = [ $@edit:after-command $_omp-after-command-hook~ ]\n\nset edit:prompt = {||\n    # Workaround to avoid a race condition in cache access.\n    while $true {\n        if (not $_omp_primary_ready) {\n            break\n        }\n    }\n\n    _omp_get_prompt primary\n\n    # Now it can start to render the right prompt.\n    set _omp_primary_ready = $true\n}\n\nset edit:rprompt = {||\n    # Workaround to avoid a race condition in cache access.\n    while $true {\n        if $_omp_primary_ready {\n            break\n        }\n    }\n\n    _omp_get_prompt right\n\n    # A \"prompt rendering period\" ends.\n    set _omp_primary_ready = $false\n}\n"
  },
  {
    "path": "src/shell/scripts/omp.fish",
    "content": "set --export --global POSH_SHELL fish\nset --export --global POSH_SHELL_VERSION $FISH_VERSION\nset --export --global POWERLINE_COMMAND oh-my-posh\nset --export --global CONDA_PROMPT_MODIFIER false\n\nset --global _omp_tooltip_command ''\nset --global _omp_current_rprompt ''\nset --global _omp_transient 0\nset --global _omp_executable ::OMP::\nset --global _omp_ftcs_marks 0\nset --global _omp_transient_prompt 0\nset --global _omp_prompt_mark 0\n\n# streaming support variables\nset --global _omp_enable_streaming 0\nset --global _omp_streaming_pid 0\nset --global _omp_streaming_tempfile ''\nset --global _omp_primary_prompt ''\n\n# disable all known python virtual environment prompts\nset --global VIRTUAL_ENV_DISABLE_PROMPT 1\nset --global PYENV_VIRTUALENV_DISABLE_PROMPT 1\n\n# We use this to avoid unnecessary CLI calls for prompt repaint.\nset --global _omp_new_prompt 1\n\n# template function for context loading\nfunction set_poshcontext\n    return\nend\n\n# cleanup stream resources\nfunction _omp_cleanup_stream\n    # kill background process if running\n    if test -n \"$_omp_streaming_pid\" -a \"$_omp_streaming_pid\" -gt 0 2>/dev/null\n        kill $_omp_streaming_pid 2>/dev/null\n        set --global _omp_streaming_pid 0\n    end\n    # remove temp file\n    if test -n \"$_omp_streaming_tempfile\"\n        rm -f \"$_omp_streaming_tempfile\" 2>/dev/null\n    end\nend\n\n# shell exit handler\nfunction _omp_exit_handler --on-event fish_exit\n    _omp_cleanup_stream\nend\n\n# streaming background reader: reads null-delimited prompts and signals parent\nfunction _omp_streaming_reader\n    set --local parent_pid $argv[1]\n    set --local tempfile $argv[2]\n    set --local count 0\n\n    # read null-delimited prompts from oh-my-posh stream\n    while read --null --local prompt\n        # write to temp file (atomic via printf)\n        printf '%s' \"$prompt\" >$tempfile\n\n        # signal parent for updates after first prompt (index > 0)\n        if test $count -gt 0\n            kill -SIGUSR1 $parent_pid 2>/dev/null\n        end\n\n        set count (math $count + 1)\n    end\nend\n\n# signal handler: called when streaming process has new prompt\nfunction _omp_streaming_handler --on-signal SIGUSR1\n    # only process if streaming is active\n    if test $_omp_enable_streaming -eq 0\n        return\n    end\n\n    if test -z \"$_omp_streaming_tempfile\" -o ! -f \"$_omp_streaming_tempfile\"\n        return\n    end\n\n    # read updated prompt from temp file\n    set --global _omp_primary_prompt (cat \"$_omp_streaming_tempfile\")\n    set --global _omp_current_prompt \"$_omp_primary_prompt\"\n\n    # trigger repaint\n    commandline --function repaint\nend\n\n# start oh-my-posh stream process, block until first prompt arrives\nfunction _omp_start_streaming\n    # cleanup any prior stream\n    _omp_cleanup_stream\n\n    # determine temp file location\n    set --local tmpdir $TMPDIR\n    if test -z \"$tmpdir\"\n        set tmpdir /tmp\n    end\n    set --global _omp_streaming_tempfile \"$tmpdir/omp-fish-$fish_pid.txt\"\n    rm -f \"$_omp_streaming_tempfile\" 2>/dev/null\n\n    # build stream command with all context\n    set --local stream_cmd $_omp_executable stream \\\n        --save-cache \\\n        --shell=fish \\\n        --shell-version=$FISH_VERSION \\\n        --status=$_omp_status \\\n        --pipestatus=\"$_omp_pipestatus\" \\\n        --no-status=$_omp_no_status \\\n        --execution-time=$_omp_execution_time \\\n        --stack-count=$_omp_stack_count\n\n    # start background reader process\n    $stream_cmd | _omp_streaming_reader $fish_pid \"$_omp_streaming_tempfile\" &\n    set --global _omp_streaming_pid (jobs --last --pid)\n\n    # block until first prompt arrives (mirrors zsh's blocking read)\n    set --local timeout 5000\n    set --local elapsed 0\n    while not test -s \"$_omp_streaming_tempfile\"\n        sleep 0.01\n        set elapsed (math $elapsed + 10)\n        if test $elapsed -ge $timeout\n            # timeout - cleanup and return failure\n            _omp_cleanup_stream\n            return 1\n        end\n    end\n\n    # read first prompt\n    set --global _omp_primary_prompt (cat \"$_omp_streaming_tempfile\")\n    set --global _omp_current_prompt \"$_omp_primary_prompt\"\n\n    return 0\nend\n\nfunction _omp_get_prompt\n    if test (count $argv) -eq 0\n        return\n    end\n    $_omp_executable print $argv[1] \\\n        --save-cache \\\n        --shell=fish \\\n        --shell-version=$FISH_VERSION \\\n        --status=$_omp_status \\\n        --pipestatus=\"$_omp_pipestatus\" \\\n        --no-status=$_omp_no_status \\\n        --execution-time=$_omp_execution_time \\\n        --stack-count=$_omp_stack_count \\\n        $argv[2..]\nend\n\n# NOTE: Input function calls via `commandline --function` are put into a queue and will not be executed until an outer regular function returns. See https://fishshell.com/docs/current/cmds/commandline.html.\n\nfunction fish_prompt\n    set --local omp_status_temp $status\n    set --local omp_pipestatus_temp $pipestatus\n    # clear from cursor to end of screen as\n    # commandline --function repaint does not do this\n    # see https://github.com/fish-shell/fish-shell/issues/8418\n    printf \\e\\[0J\n    if test \"$_omp_transient\" = 1\n        _omp_get_prompt transient\n        return\n    end\n    if test \"$_omp_new_prompt\" = 0\n        echo -n \"$_omp_current_prompt\"\n        return\n    end\n    set --global _omp_status $omp_status_temp\n    set --global _omp_pipestatus $omp_pipestatus_temp\n    set --global _omp_no_status false\n    set --global _omp_execution_time \"$CMD_DURATION$cmd_duration\"\n    set --global _omp_stack_count (count $dirstack)\n\n    # check if variable set, < 3.2 case\n    if set --query _omp_last_command && test -z \"$_omp_last_command\"\n        set _omp_execution_time 0\n        set _omp_no_status true\n    end\n\n    # works with fish >=3.2\n    if set --query _omp_last_status_generation && test \"$_omp_last_status_generation\" = \"$status_generation\"\n        set _omp_execution_time 0\n        set _omp_no_status true\n    else if test -z \"$_omp_last_status_generation\"\n        # first execution - $status_generation is 0, $_omp_last_status_generation is empty\n        set _omp_no_status true\n    end\n\n    if set --query status_generation\n        set --global _omp_last_status_generation $status_generation\n    end\n\n    set_poshcontext\n\n    # validate if the user cleared the screen\n    set --local omp_cleared false\n    set --local last_command (history search --max 1)\n\n    if test \"$last_command\" = clear\n        set omp_cleared true\n    end\n\n    if test $_omp_prompt_mark = 1\n        iterm2_prompt_mark\n    end\n\n    # === STREAMING PATH ===\n    if test $_omp_enable_streaming -eq 1\n        # start new streaming session (blocks until first prompt arrives)\n        if _omp_start_streaming\n            # _omp_current_prompt already set by _omp_start_streaming\n            echo -n \"$_omp_current_prompt\"\n            return\n        end\n        # fall through to sync on failure\n    end\n\n    # === FALLBACK PATH ===\n    # The prompt is saved for possible reuse, typically a repaint after clearing the screen buffer.\n    set --global _omp_current_prompt (_omp_get_prompt primary --cleared=$omp_cleared | string join \\n | string collect)\n\n    echo -n \"$_omp_current_prompt\"\nend\n\nfunction fish_right_prompt\n    if test \"$_omp_transient\" = 1\n        set --global _omp_transient 0\n        return\n    end\n\n    # Repaint an existing right prompt.\n    if test \"$_omp_new_prompt\" = 0\n        echo -n \"$_omp_current_rprompt\"\n        return\n    end\n\n    set --global _omp_new_prompt 0\n    set --global _omp_current_rprompt (_omp_get_prompt right | string join '')\n\n    echo -n \"$_omp_current_rprompt\"\nend\n\nfunction _omp_postexec --on-event fish_postexec\n    # works with fish <3.2\n    # pre and postexec not fired for empty command in fish >=3.2\n    set --global _omp_last_command $argv\nend\n\nfunction _omp_preexec --on-event fish_preexec\n    if test $_omp_ftcs_marks = 1\n        echo -ne \"\\e]133;C\\a\"\n    end\nend\n\n# perform cleanup so a new initialization in current session works\nif bind \\r --user 2>/dev/null | string match -qe _omp_enter_key_handler\n    bind -e \\r -M default\n    bind -e \\r -M insert\n    bind -e \\r -M visual\nend\n\nif bind \\n --user 2>/dev/null | string match -qe _omp_enter_key_handler\n    bind -e \\n -M default\n    bind -e \\n -M insert\n    bind -e \\n -M visual\nend\n\nif bind \\cc --user 2>/dev/null | string match -qe _omp_ctrl_c_key_handler\n    bind -e \\cc -M default\n    bind -e \\cc -M insert\n    bind -e \\cc -M visual\nend\n\nif bind \\x20 --user 2>/dev/null | string match -qe _omp_space_key_handler\n    bind -e \\x20 -M default\n    bind -e \\x20 -M insert\nend\n\n# tooltip\n\nfunction _omp_space_key_handler\n    commandline --function expand-abbr\n    commandline --insert ' '\n\n    # Get the first word of command line as tip.\n    set --local tooltip_command (commandline --current-buffer | string trim -l | string split --allow-empty -f1 ' ' | string collect)\n\n    # Ignore an empty/repeated tooltip command.\n    if test -z \"$tooltip_command\" || test \"$tooltip_command\" = \"$_omp_tooltip_command\"\n        return\n    end\n\n    set _omp_tooltip_command $tooltip_command\n    set --local tooltip_prompt (_omp_get_prompt tooltip --command=$_omp_tooltip_command | string join '')\n\n    if test -z \"$tooltip_prompt\"\n        return\n    end\n\n    # Save the tooltip prompt to avoid unnecessary CLI calls.\n    set _omp_current_rprompt $tooltip_prompt\n    commandline --function repaint\nend\n\nfunction enable_poshtooltips\n    bind \\x20 _omp_space_key_handler -M default\n    bind \\x20 _omp_space_key_handler -M insert\nend\n\n# transient prompt\n\nfunction _omp_enter_key_handler\n    if commandline --paging-mode\n        commandline --function execute\n        return\n    end\n\n    if commandline --is-valid || test -z (commandline --current-buffer | string trim -l | string collect)\n        set --global _omp_new_prompt 1\n        set --global _omp_tooltip_command ''\n\n        # cleanup streaming before executing command\n        _omp_cleanup_stream\n\n        if test $_omp_transient_prompt = 1\n            set --global _omp_transient 1\n            commandline --function repaint\n        end\n    end\n\n    commandline --function execute\nend\n\nfunction _omp_ctrl_c_key_handler\n    if test -z (commandline --current-buffer | string collect)\n        return\n    end\n\n    # Render a transient prompt on Ctrl-C with non-empty command line buffer.\n    set --global _omp_new_prompt 1\n    set --global _omp_tooltip_command ''\n\n    # cleanup streaming before canceling\n    _omp_cleanup_stream\n\n    if test $_omp_transient_prompt = 1\n        set --global _omp_transient 1\n        commandline --function repaint\n    end\n\n    commandline --function cancel-commandline\n    commandline --function repaint\nend\n\nbind \\r _omp_enter_key_handler -M default\nbind \\r _omp_enter_key_handler -M insert\nbind \\r _omp_enter_key_handler -M visual\nbind \\n _omp_enter_key_handler -M default\nbind \\n _omp_enter_key_handler -M insert\nbind \\n _omp_enter_key_handler -M visual\nbind \\cc _omp_ctrl_c_key_handler -M default\nbind \\cc _omp_ctrl_c_key_handler -M insert\nbind \\cc _omp_ctrl_c_key_handler -M visual\n\n# legacy functions\nfunction enable_poshtransientprompt\n    return\nend\n\n# This can be called by user whenever re-rendering is required.\nfunction omp_repaint_prompt\n    set --global _omp_new_prompt 1\n    commandline --function repaint\nend\n"
  },
  {
    "path": "src/shell/scripts/omp.lua",
    "content": "---@diagnostic disable: undefined-global\n---@diagnostic disable: undefined-field\n---@diagnostic disable: lowercase-global\n\n-- Environment variables\nos.setenv('POSH_SHELL', 'cmd')\n\n-- disable all known python virtual environment prompts\nos.setenv('VIRTUAL_ENV_DISABLE_PROMPT', '1')\nos.setenv('PYENV_VIRTUALENV_DISABLE_PROMPT', '1')\n\n-- Helper functions\n\nlocal function get_priority_number(name, default)\n    local value = os.getenv(name)\n    if value == nil and os.envmap ~= nil and type(os.envmap) == 'table' then\n        value = os.envmap[name]\n    end\n    local num = tonumber(value)\n    if num ~= nil then\n        return num\n    end\n    return default\nend\n\n-- Environment variables\n\nlocal function environment_onbeginedit()\n\nend\n\n-- Local state\n\nlocal endedit_time = 0\nlocal last_duration = 0\nlocal rprompt_enabled = false\nlocal transient_enabled = false\nlocal ftcs_marks_enabled = false\nlocal no_exit_code = true\n\nlocal cached_prompt = {}\n-- Fields in cached_prompt:\n--      .cwd            = Current working directory of prompt.\n--      .left           = Left side prompt.\n--      .right          = Right side prompt.\n--      .tooltip        = Tooltip prompt.\n--      .tip_command    = Command for which to produce a tooltip.\n--      .coroutine      = Coroutine for the tooltip prompt.\n\nlocal function cache_onbeginedit()\n    local cwd = os.getcwd()\n    local old_cache = cached_prompt\n\n    -- Start a new table for the new edit/prompt session.\n    cached_prompt = { cwd = cwd }\n\n    -- Copy the cached left/right prompt strings if the cwd hasn't changed.\n    -- IMPORTANT OPTIMIZATION:  This keeps the prompt highly responsive, except\n    -- when changing the current working directory.\n    if old_cache.cwd == cwd then\n        cached_prompt.left = old_cache.left\n        cached_prompt.right = old_cache.right\n    end\nend\n\n-- Executable\n\nlocal omp_executable = '::OMP::'\n\n-- Configuration\n\nos.setenv('POSH_SHELL_VERSION', string.format('clink v%s.%s.%s.%s', clink.version_major, clink.version_minor, clink.version_patch, clink.version_commit))\n\n-- Execution helpers\n\nlocal function can_async()\n    if (clink.version_encoded or 0) >= 10030001 then\n        return settings.get('prompt.async')\n    end\nend\n\nlocal function run_posh_command(command)\n    command = string.format('\"\"%s\" %s\"', omp_executable, command)\n    local _, is_main = coroutine.running()\n    local f, msg\n    if is_main then\n        f, msg = io.popen(command)\n    else\n        f, msg = io.popenyield(command)\n    end\n    local output = ''\n    if f then\n        output = f:read('*a')\n        f:close()\n    else\n        if msg and msg:sub(1, #command) == command then\n            msg = msg:sub(#command + 1)\n            msg = msg:gsub('^: +', '')\n            if msg == '' then\n                msg = nil\n            end\n        end\n        local cwd = os.getcwd()\n        cwd = cwd and (' in ' .. cwd) or ''\n        msg = msg and (' (' .. msg .. ')') or ''\n        log.info(string.format('Unable to run oh-my-posh%s%s.', msg, cwd))\n        log.info(command)\n    end\n    return output\nend\n\n-- Duration functions\n\nlocal function os_clock_millis()\n    -- Clink v1.2.30 has a fix for Lua's os.clock() implementation failing after\n    -- the program has been running more than 24 days.  In older versions, call\n    -- OMP to get the time in milliseconds.\n    if (clink.version_encoded or 0) >= 10020030 then\n        return math.floor(os.clock() * 1000)\n    end\n    return run_posh_command('get millis')\nend\n\nlocal function duration_onbeginedit()\n    last_duration = 0\n    if endedit_time ~= 0 then\n        local beginedit_time = tonumber(os_clock_millis())\n        if beginedit_time then\n            local elapsed = beginedit_time - endedit_time\n            if elapsed >= 0 then\n                last_duration = elapsed\n            end\n        end\n    end\nend\n\nlocal function duration_onendedit(input)\n    endedit_time = 0\n    -- For an empty command, the execution time should not be evaluated.\n    if string.gsub(input, '^%s*(.-)%s*$', '%1') ~= '' then\n        local m = tonumber(os_clock_millis())\n        if m then\n            endedit_time = m\n        end\n    end\nend\n\n-- Prompt functions\n\nlocal function execution_time_option()\n    if last_duration ~= nil then\n        return '--execution-time=' .. last_duration\n    end\n    return ''\nend\n\nlocal function status_option()\n    if os.geterrorlevel ~= nil and settings.get('cmd.get_errorlevel') then\n        return '--status=' .. os.geterrorlevel()\n    end\n    return ''\nend\n\nlocal function no_status_option()\n    if no_exit_code then\n        return '--no-status'\n    end\n    return ''\nend\n\nlocal function get_posh_prompt(prompt_type, ...)\n    os.setenv('POSH_CURSOR_LINE', console.getnumlines())\n    local command = table.concat({\n        'print',\n        prompt_type,\n        '--save-cache',\n        '--shell=cmd',\n        status_option(),\n        no_status_option(),\n        execution_time_option(),\n        ...\n    }, ' ')\n    return run_posh_command(command)\nend\n\nlocal function set_posh_tooltip(tip_command)\n    if tip_command ~= '' and tip_command ~= cached_prompt.tip_command then\n        -- Escape special characters properly, if any.\n        local escaped_tip_command = string.gsub(tip_command, '(\\\\+)\"', '%1%1\"'):gsub('(\\\\+)$', '%1%1'):gsub('\"', '\\\\\"'):gsub('([&<>%(%)@|%^])', '^%1'):gsub('%%', '%%%%')\n        local command_option = string.format('--command \"%s\"', escaped_tip_command)\n        local tooltip = get_posh_prompt('tooltip', command_option)\n        -- Do not cache an empty tooltip.\n        if tooltip == '' then\n            return\n        end\n        cached_prompt.tip_command = tip_command\n        cached_prompt.tooltip = tooltip\n    end\nend\n\nlocal function display_cached_prompt()\n    -- Use what's already cached; avoid running oh-my-posh.\n    cached_prompt.only_use_cache = true\n    clink.refilterprompt()\n    cached_prompt.only_use_cache = nil\nend\n\nlocal function command_executed_mark(input)\n    if string.gsub(input, '^%s*(.-)%s*$', '%1') ~= '' then\n        no_exit_code = false\n    end\n    if ftcs_marks_enabled then\n        clink.print('\\x1b]133;C\\007', NONL)\n    end\nend\n\n-- set priority lower than z.lua\n-- https://github.com/skywind3000/z.lua/pull/125/commits/48a77adf3575952b2e951aa820a1ce11ed4ce56b\nlocal zl_prompt_priority = get_priority_number('_ZL_CLINK_PROMPT_PRIORITY', 0)\nlocal p = clink.promptfilter(zl_prompt_priority + 1)\nfunction p:filter(prompt)\n    local need_left = true\n\n    -- Get a left prompt immediately if nothing is available yet.\n    if not cached_prompt.left then\n        cached_prompt.left = get_posh_prompt('primary')\n        need_left = false\n    end\n\n    -- Get left/right prompts asynchronously, if possible.\n    if not cached_prompt.only_use_cache then\n        if can_async() then\n            -- IMPORTANT:  Defining this function inline makes sure it only\n            -- updates the same cached_prompt table that existed when the\n            -- function was defined.  That way if a new prompt starts (which\n            -- discards the old coroutine) and a new coroutine starts, the old\n            -- coroutine won't stomp on the new cached_prompt table.\n            clink.promptcoroutine(function()\n                -- Generate left prompt, if needed.\n                if need_left then\n                    cached_prompt.left = get_posh_prompt('primary')\n                end\n                -- Generate right prompt, if needed.\n                if rprompt_enabled then\n                    if need_left then\n                        -- Show left side while right side is being generated.\n                        display_cached_prompt()\n                    end\n                    cached_prompt.right = get_posh_prompt('right')\n                else\n                    cached_prompt.right = nil\n                end\n            end)\n        else\n            if need_left then\n                cached_prompt.left = get_posh_prompt('primary')\n            end\n            if rprompt_enabled then\n                cached_prompt.right = get_posh_prompt('right')\n            end\n        end\n    end\n\n    if cached_prompt.left == nil or cached_prompt.left == '' then\n        cached_prompt.left = string.format('Unable to get prompt text; see clink.log file for details.\\n%s>', os.getcwd() or '')\n    end\n\n    return cached_prompt.left\nend\n\nfunction p:rightfilter(prompt)\n    -- Return cached tooltip if available, otherwise return cached rprompt.\n    -- Returning false as the second return value halts further prompt\n    -- filtering, to keep other things from overriding what we generated.\n    return (cached_prompt.tooltip or cached_prompt.right), false\nend\n\nfunction p:transientfilter(prompt)\n    if not transient_enabled then\n        return nil\n    end\n\n    prompt = get_posh_prompt('transient')\n\n    if prompt == '' then\n        prompt = nil\n    end\n\n    return prompt\nend\n\nfunction p:transientrightfilter(prompt)\n    return '', false\nend\n\n-- Event handlers\n\nlocal function builtin_modules_onbeginedit()\n    cache_onbeginedit()\n    duration_onbeginedit()\n    environment_onbeginedit()\nend\n\nlocal function builtin_modules_onendedit(input)\n    duration_onendedit(input)\n    command_executed_mark(input)\nend\n\nif clink.onbeginedit ~= nil and clink.onendedit ~= nil then\n    clink.onbeginedit(builtin_modules_onbeginedit)\n    clink.onendedit(builtin_modules_onendedit)\nend\n\n-- Tooltips\n\nfunction _omp_space_keybinding(rl_buffer)\n    -- Insert space first, in case it might affect the tip word, e.g. it could\n    -- split \"gitcommit\" into \"git commit\".\n    rl_buffer:insert(' ')\n    -- Get the first word of command line as tip.\n    local tip_command = rl_buffer:getbuffer():gsub('^%s*(.-)%s*$', '%1')\n\n    -- Generate a tooltip asynchronously (via coroutine) if available, otherwise\n    -- generate a tooltip immediately.\n    if not can_async() then\n        set_posh_tooltip(tip_command)\n        clink.refilterprompt()\n    elseif cached_prompt.coroutine then\n        -- No action needed; a tooltip coroutine is already running.\n    else\n        cached_prompt.coroutine = coroutine.create(function()\n            set_posh_tooltip(tip_command)\n            if cached_prompt.coroutine == coroutine.running() then\n                cached_prompt.coroutine = nil\n            end\n            display_cached_prompt()\n        end)\n    end\nend\n\nlocal function enable_tooltips()\n    if not rl.setbinding then\n        return\n    end\n\n    rl.setbinding(' ', [[\"luafunc:_omp_space_keybinding\"]], 'emacs')\nend\n"
  },
  {
    "path": "src/shell/scripts/omp.nu",
    "content": "# make sure we have the right prompt render correctly\nif ($env.config? | is-not-empty) {\n    $env.config = ($env.config | upsert render_right_prompt_on_last_line true)\n}\n\n$env.POWERLINE_COMMAND = 'oh-my-posh'\n$env.PROMPT_INDICATOR = \"\"\n$env.POSH_SESSION_ID = \"::SESSION_ID::\"\n$env.POSH_SHELL = \"nu\"\n$env.POSH_SHELL_VERSION = (version | get version)\n\n# disable all known python virtual environment prompts\n$env.VIRTUAL_ENV_DISABLE_PROMPT = 1\n$env.PYENV_VIRTUALENV_DISABLE_PROMPT = 1\n\nlet _omp_executable: string = (echo ::OMP::)\n\n# PROMPTS\n\ndef --wrapped _omp_get_prompt [\n    type: string,\n    ...args: string\n] {\n    mut execution_time = -1\n    mut no_status = true\n    # We have to do this because the initial value of `$env.CMD_DURATION_MS` is always `0823`, which is an official setting.\n    # See https://github.com/nushell/nushell/discussions/6402#discussioncomment-3466687.\n    if $env.CMD_DURATION_MS != '0823' {\n        $execution_time = $env.CMD_DURATION_MS\n        $no_status = false\n    }\n\n    (\n        ^$_omp_executable print $type\n            --save-cache\n            --shell=nu\n            $\"--shell-version=($env.POSH_SHELL_VERSION)\"\n            $\"--status=($env.LAST_EXIT_CODE)\"\n            $\"--no-status=($no_status)\"\n            $\"--execution-time=($execution_time)\"\n            $\"--terminal-width=((term size).columns)\"\n            $\"--job-count=(job list | length)\"\n            ...$args\n    )\n}\n\n$env.PROMPT_MULTILINE_INDICATOR = (\n    ^$_omp_executable print secondary\n        --shell=nu\n        $\"--shell-version=($env.POSH_SHELL_VERSION)\"\n)\n\n$env.PROMPT_COMMAND = {||\n    # hack to set the cursor line to 1 when the user clears the screen\n    # this obviously isn't bulletproof, but it's a start\n    mut clear = false\n    if $nu.history-enabled {\n        $clear = (history | is-empty) or ((history | last 1 | get 0.command) == \"clear\")\n    }\n\n    if ($env.SET_POSHCONTEXT? | is-not-empty) {\n        do --env $env.SET_POSHCONTEXT\n    }\n\n    _omp_get_prompt primary $\"--cleared=($clear)\"\n}\n\n$env.PROMPT_COMMAND_RIGHT = {|| _omp_get_prompt right }\n"
  },
  {
    "path": "src/shell/scripts/omp.ps1",
    "content": "# remove any existing dynamic module of OMP\nif ($null -ne (Get-Module -Name \"oh-my-posh-core\")) {\n    Remove-Module -Name \"oh-my-posh-core\" -Force\n}\n\n# disable all known python virtual environment prompts\n$env:VIRTUAL_ENV_DISABLE_PROMPT = 1\n$env:PYENV_VIRTUALENV_DISABLE_PROMPT = 1\n\n# Helper functions which need to be defined before the module is loaded\n# See https://github.com/JanDeDobbeleer/oh-my-posh/discussions/2300\nfunction global:Get-PoshStackCount {\n    $locations = Get-Location -Stack\n    if ($locations) {\n        return $locations.Count\n    }\n    return 0\n}\n\n# global enablers\n$global:_ompJobCount = $false\n$global:_ompFTCSMarks = $false\n$global:_ompPoshGit = $false\n$global:_ompAzure = $false\n$global:_ompExecutable = ::OMP::\n$global:_ompTransientPrompt = $false\n$global:_ompStreaming = $false\n\nNew-Module -Name \"oh-my-posh-core\" -ScriptBlock {\n    # Check `ConstrainedLanguage` mode.\n    $script:ConstrainedLanguageMode = $ExecutionContext.SessionState.LanguageMode -eq \"ConstrainedLanguage\"\n\n    # Prompt related backup.\n    $script:OriginalPromptFunction = $Function:prompt\n    $script:OriginalContinuationPrompt = (Get-PSReadLineOption).ContinuationPrompt\n    $script:OriginalPromptText = (Get-PSReadLineOption).PromptText\n\n    $script:NoExitCode = $true\n    $script:ErrorCode = 0\n    $script:ExecutionTime = 0\n    $script:ShellName = \"pwsh\"\n    $script:PSVersion = $PSVersionTable.PSVersion.ToString()\n    $script:TransientPrompt = $false\n    $script:TooltipCommand = ''\n    $script:JobCount = 0\n    $script:Streaming = [hashtable]::Synchronized(@{\n            Process     = $null\n            # Runspace    = $null\n            AsyncResult = $null\n            Prompt      = ''\n            State       = 'NEW'\n        })\n\n    $env:POWERLINE_COMMAND = \"oh-my-posh\"\n    $env:POSH_SHELL = \"pwsh\"\n    $env:POSH_SHELL_VERSION = $script:PSVersion\n    $env:CONDA_PROMPT_MODIFIER = $false\n\n    function Invoke-Utf8Posh {\n        param([string[]]$Arguments = @())\n\n        if ($script:ConstrainedLanguageMode) {\n            $output = Invoke-Expression \"& `$global:_ompExecutable `$Arguments 2>&1\"\n            $output -join \"`n\"\n            return\n        }\n\n        $Process = New-Object System.Diagnostics.Process\n        $StartInfo = $Process.StartInfo\n        $StartInfo.FileName = $global:_ompExecutable\n        if ($StartInfo.ArgumentList.Add) {\n            # ArgumentList is supported in PowerShell 6.1 and later (built on .NET Core 2.1+)\n            # ref-1: https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0\n            # ref-2: https://docs.microsoft.com/en-us/powershell/scripting/whats-new/differences-from-windows-powershell?view=powershell-7.2#net-framework-vs-net-core\n            $Arguments | ForEach-Object -Process { $StartInfo.ArgumentList.Add($_) }\n        }\n        else {\n            # escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)\n            $escapedArgs = $Arguments | ForEach-Object {\n                # escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones\n                $s = $_ -replace '(\\\\+)\"', '$1$1\"'\n                # escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones\n                $s = $s -replace '(\\\\+)$', '$1$1'\n                # escape double quotes\n                $s = $s -replace '\"', '\\\"'\n                # quote the argument\n                \"`\"$s`\"\"\n            }\n            $StartInfo.Arguments = $escapedArgs -join ' '\n        }\n\n        $StartInfo.StandardErrorEncoding = $StartInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8\n        $StartInfo.RedirectStandardError = $StartInfo.RedirectStandardInput = $StartInfo.RedirectStandardOutput = $true\n        $StartInfo.UseShellExecute = $false\n        if ($PWD.Provider.Name -eq 'FileSystem') {\n            # make sure we're in a valid directory\n            # if not, go back HOME\n            if (-not (Test-Path -LiteralPath $PWD)) {\n                Write-Host \"Unable to find the current directory, falling back to $HOME\" -ForegroundColor Red\n                Set-Location $HOME\n            }\n            $StartInfo.WorkingDirectory = $PWD.ProviderPath\n        }\n\n        $StartInfo.CreateNoWindow = $true\n        [void]$Process.Start()\n\n        # Remove deadlock potential on Windows.\n        $stdoutTask = $Process.StandardOutput.ReadToEndAsync()\n        $stderrTask = $Process.StandardError.ReadToEndAsync()\n\n        $Process.WaitForExit()\n        $stderr = $stderrTask.Result.Trim()\n        if ($stderr) {\n            $Host.UI.WriteErrorLine($stderr)\n        }\n\n        $stdoutTask.Result\n    }\n\n    function Get-NonFSWD {\n        # We only need to return a non-filesystem working directory.\n        if ($PWD.Provider.Name -ne 'FileSystem') {\n            return $PWD.ToString()\n        }\n    }\n\n    function Get-TerminalWidth {\n        $terminalWidth = $Host.UI.RawUI.WindowSize.Width\n        # Set a sane default when the value can't be retrieved.\n        if (-not $terminalWidth) {\n            return 0\n        }\n        $terminalWidth\n    }\n\n    function Set-TransientPrompt {\n        $previousOutputEncoding = [Console]::OutputEncoding\n        try {\n            $script:TransientPrompt = $true\n            [Console]::OutputEncoding = [Text.Encoding]::UTF8\n            [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()\n        }\n        catch [System.ArgumentOutOfRangeException] {\n        }\n        finally {\n            [Console]::OutputEncoding = $previousOutputEncoding\n        }\n    }\n\n    function Set-PoshPromptType {\n        if ($script:TransientPrompt -eq $true) {\n            $script:PromptType = \"transient\"\n            $script:TransientPrompt = $false\n            return\n        }\n\n        # for details about the trick to detect a debugging context, see these comments:\n        # 1) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2483#issuecomment-1175761456\n        # 2) https://github.com/JanDeDobbeleer/oh-my-posh/issues/2502#issuecomment-1179968052\n        # 3) https://github.com/JanDeDobbeleer/oh-my-posh/issues/5153\n        if ($Host.Runspace.Debugger.InBreakpoint) {\n            $script:PromptType = \"debug\"\n            return\n        }\n\n        $script:PromptType = \"primary\"\n\n        if ($global:_ompJobCount) {\n            $script:JobCount = (Get-Job -State Running).Count\n        }\n\n        if ($global:_ompAzure) {\n            try {\n                $env:POSH_AZURE_SUBSCRIPTION = Get-AzContext | ConvertTo-Json\n            }\n            catch {\n            }\n        }\n\n        if ($global:_ompPoshGit) {\n            try {\n                $global:GitStatus = Get-GitStatus\n                $env:POSH_GIT_STATUS = $global:GitStatus | ConvertTo-Json\n            }\n            catch {\n            }\n        }\n    }\n\n    function Update-PoshErrorCode {\n        $lastHistory = Get-History -ErrorAction Ignore -Count 1\n\n        # error code should be updated only when a non-empty command is run\n        if (($null -eq $lastHistory) -or ($script:LastHistoryId -eq $lastHistory.Id)) {\n            $script:ExecutionTime = 0\n            $script:NoExitCode = $true\n            return\n        }\n\n        $script:NoExitCode = $false\n        $script:LastHistoryId = $lastHistory.Id\n        $script:ExecutionTime = ($lastHistory.EndExecutionTime - $lastHistory.StartExecutionTime).TotalMilliseconds\n        if ($script:OriginalLastExecutionStatus) {\n            $script:ErrorCode = 0\n            return\n        }\n\n        $invocationInfo = try {\n            # retrieve info of the most recent error\n            $global:Error | Where-Object { $_.GetType().Name -eq 'ErrorRecord' } | Select-Object -First 1 -ExpandProperty InvocationInfo\n        }\n        catch {\n            $null\n        }\n\n        # Check if the error occurred in the current command scope\n        if ($null -ne $invocationInfo -and\n            $invocationInfo.HistoryId -eq $lastHistory.Id) {\n            $script:ErrorCode = 1\n            return\n        }\n\n        if ($script:OriginalLastExitCode -is [int] -and $script:OriginalLastExitCode -ne 0) {\n            # native app exit code\n            $script:ErrorCode = $script:OriginalLastExitCode\n            return\n        }\n    }\n\n    function Get-PoshPrompt {\n        param(\n            [string]$Type,\n            [string[]]$Arguments\n        )\n        $nonFSWD = Get-NonFSWD\n        $stackCount = Get-PoshStackCount\n        $terminalWidth = Get-TerminalWidth\n        Invoke-Utf8Posh @(\n            \"print\", $Type\n            \"--save-cache\"\n            \"--shell=$script:ShellName\"\n            \"--shell-version=$script:PSVersion\"\n            \"--status=$script:ErrorCode\"\n            \"--no-status=$script:NoExitCode\"\n            \"--execution-time=$script:ExecutionTime\"\n            \"--pswd=$nonFSWD\"\n            \"--stack-count=$stackCount\"\n            \"--terminal-width=$terminalWidth\"\n            \"--job-count=$script:JobCount\"\n            if ($Arguments) {\n                $Arguments\n            }\n        )\n    }\n\n    function Stop-StreamingProcess {\n        if (-not $global:_ompStreaming) {\n            return\n        }\n\n        Unregister-Event -SourceIdentifier \"OhMyPoshStreaming\" -ErrorAction Ignore\n        Get-Job -Name \"OhMyPoshStreaming\" -ErrorAction Ignore | Remove-Job -Force\n\n        # Then kill the streaming process\n        if ($null -ne $script:Streaming.Process -and -not $script:Streaming.Process.HasExited) {\n            try {\n                $script:Streaming.Process.Kill()\n            }\n            catch {\n            }\n        }\n\n        $script:Streaming.Process = $null\n        $script:Streaming.State = 'NEW'\n    }\n\n    function Get-PoshStreamingPrompt {\n        # Start streaming process (State stays 'NEW' until initial prompt fully rendered)\n        $script:Streaming.Process = New-Object System.Diagnostics.Process\n        $StartInfo = $script:Streaming.Process.StartInfo\n        $StartInfo.FileName = $global:_ompExecutable\n\n        # Build arguments array\n        $Arguments = @(\n            \"stream\"\n            \"--save-cache\"\n            \"--shell=$script:ShellName\"\n            \"--shell-version=$script:PSVersion\"\n            \"--status=$script:ErrorCode\"\n            \"--no-status=$script:NoExitCode\"\n            \"--execution-time=$script:ExecutionTime\"\n            \"--pswd=$(Get-NonFSWD)\"\n            \"--stack-count=$(Get-PoshStackCount)\"\n            \"--terminal-width=$(Get-TerminalWidth)\"\n            \"--job-count=$script:JobCount\"\n        )\n\n        # Use ArgumentList if available (PowerShell 6.1+), otherwise escape manually\n        if ($StartInfo.ArgumentList.Add) {\n            $Arguments | ForEach-Object -Process { $StartInfo.ArgumentList.Add($_) }\n        }\n        else {\n            # escape arguments manually in lower versions, refer to https://docs.microsoft.com/en-us/previous-versions/17w5ykft(v=vs.85)\n            $escapedArgs = $Arguments | ForEach-Object {\n                # escape N consecutive backslash(es), which are followed by a double quote, to 2N consecutive ones\n                $s = $_ -replace '(\\\\+)\"', '$1$1\"'\n                # escape N consecutive backslash(es), which are at the end of the string, to 2N consecutive ones\n                $s = $s -replace '(\\\\+)$', '$1$1'\n                # escape double quotes\n                $s = $s -replace '\"', '\\\"'\n                # quote the argument\n                \"`\"$s`\"\"\n            }\n            $StartInfo.Arguments = $escapedArgs -join ' '\n        }\n\n        $StartInfo.StandardOutputEncoding = [System.Text.Encoding]::UTF8\n        $StartInfo.RedirectStandardOutput = $true\n        $StartInfo.UseShellExecute = $false\n        $StartInfo.CreateNoWindow = $true\n        if ($PWD.Provider.Name -eq 'FileSystem') {\n            $StartInfo.WorkingDirectory = $PWD.ProviderPath\n        }\n\n        [void]$script:Streaming.Process.Start()\n\n        # Read output asynchronously\n        $output = New-Object 'System.Management.Automation.PSDataCollection[PSObject]'\n        $inputData = New-Object 'System.Management.Automation.PSDataCollection[PSObject]'\n        $inputData.Complete()\n        $ps = [powershell]::Create().AddScript({\n                param($stream)\n                while ($true) {\n                    $bytes = [System.Collections.Generic.List[byte]]::new()\n                    while (($b = $stream.ReadByte()) -notin -1, 0) {\n                        $bytes.Add($b)\n                    }\n\n                    if ($bytes.Count -gt 0) {\n                        Write-Output ([Text.Encoding]::UTF8.GetString($bytes.ToArray()))\n                    }\n\n                    if ($b -eq -1) {\n                        return\n                    }\n                }\n            }).AddArgument($script:Streaming.Process.StandardOutput.BaseStream)\n\n        $ps.BeginInvoke($inputData, $output) | Out-Null\n\n        # Update prompt when output arrives\n        Register-ObjectEvent -InputObject $output -EventName DataAdded -SourceIdentifier \"OhMyPoshStreaming\" -MessageData @{\n            Streaming = $script:Streaming\n        } -Action {\n            $s = $event.MessageData.Streaming\n            $index = $event.SourceEventArgs.Index\n\n            if ($index -eq 0 -or $s.State -ne 'RUNNING') {\n                return\n            }\n\n            $previousOutputEncoding = [Console]::OutputEncoding\n\n            try {\n                [Console]::OutputEncoding = [Text.Encoding]::UTF8\n                $s.Prompt = $event.SourceArgs[0][$index]\n                [Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()\n            }\n            catch {}\n            finally {\n                [Console]::OutputEncoding = $previousOutputEncoding\n            }\n        } | Out-Null\n\n        while ($output.Count -eq 0) {\n            Start-Sleep -Milliseconds 1\n        }\n\n        $script:Streaming.Prompt = $output[0]\n        return $script:Streaming.Prompt\n    }\n\n    $promptFunction = {\n        # store the original last command execution status\n        if ($global:NVS_ORIGINAL_LASTEXECUTIONSTATUS -is [bool]) {\n            # make it compatible with NVS auto-switching, if enabled\n            $script:OriginalLastExecutionStatus = $global:NVS_ORIGINAL_LASTEXECUTIONSTATUS\n        }\n        else {\n            $script:OriginalLastExecutionStatus = $?\n        }\n\n        # store the original last exit code\n        $script:OriginalLastExitCode = $global:LASTEXITCODE\n\n        # Only return cached prompt if we're in a streaming redraw (RUNNING state)\n        # AND it's not a transient prompt. Don't use cached prompt for FINAL state\n        # as that means the previous prompt is complete and we need a fresh one.\n        if ($script:PromptType -ne 'transient' -and $script:Streaming.State -ne 'NEW') {\n            # Update ExtraPromptLineCount for PSReadLine to properly clear previous prompt\n            Set-PSReadLineOption -ExtraPromptLineCount (($script:Streaming.Prompt | Measure-Object -Line).Lines - 1)\n            return $script:Streaming.Prompt\n        }\n\n        # Stop any previous streaming process and reset state\n        Stop-StreamingProcess\n\n        # Reset tooltip command.\n        $script:TooltipCommand = ''\n\n        Set-PoshPromptType\n\n        if ($script:PromptType -ne 'transient') {\n            Update-PoshErrorCode\n        }\n\n        Set-PoshContext $script:ErrorCode\n\n        # set the cursor positions, they are zero based so align with other platforms\n        $env:POSH_CURSOR_LINE = $Host.UI.RawUI.CursorPosition.Y + 1\n        $env:POSH_CURSOR_COLUMN = $Host.UI.RawUI.CursorPosition.X + 1\n\n        # Use streaming prompt if enabled, otherwise use regular prompt\n        if ($global:_ompStreaming -and $script:PromptType -eq 'primary') {\n            $output = Get-PoshStreamingPrompt\n        }\n        else {\n            $output = Get-PoshPrompt $script:PromptType\n        }\n\n        # make sure PSReadLine knows if we have a multiline prompt\n        Set-PSReadLineOption -ExtraPromptLineCount (($output | Measure-Object -Line).Lines - 1)\n\n        # The output can be multi-line, joining them ensures proper rendering.\n        $output = $output -join \"`n\"\n\n        if ($script:PromptType -eq 'transient') {\n            # Workaround to prevent a command from eating the tail of a transient prompt, when we're at the end of the line.\n            $command = ''\n            [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)\n            if ($command) {\n                $output += \"  `b`b\"\n            }\n        }\n\n        # Now that we're about to return, mark streaming as ready for updates\n        if ($global:_ompStreaming -and $script:PromptType -eq 'primary') {\n            $script:Streaming.State = 'RUNNING'\n        }\n\n        $output\n\n        # remove any posh-git status\n        $env:POSH_GIT_STATUS = $null\n\n        # restore the original last exit code\n        $global:LASTEXITCODE = $script:OriginalLastExitCode\n    }\n\n    $Function:prompt = $promptFunction\n\n    # set secondary prompt\n    Set-PSReadLineOption -ContinuationPrompt ((Invoke-Utf8Posh @(\"print\", \"secondary\", \"--shell=$script:ShellName\")) -join \"`n\")\n\n    ### Exported Functions ###\n\n    function Set-PoshContext([bool]$originalStatus) {\n    }\n\n    function Enable-PoshTooltips {\n        if ($script:ConstrainedLanguageMode) {\n            return\n        }\n\n        Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {\n            param([ConsoleKeyInfo]$key)\n            [Microsoft.PowerShell.PSConsoleReadLine]::SelfInsert($key)\n            try {\n                $command = ''\n                [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)\n                # Get the first word of command line as tip.\n                $command = $command.TrimStart().Split(' ', 2) | Select-Object -First 1\n\n                # Ignore an empty/repeated tooltip command.\n                if (!$command -or ($command -eq $script:TooltipCommand)) {\n                    return\n                }\n\n                $script:TooltipCommand = $command\n\n                $output = (Get-PoshPrompt \"tooltip\" @(\n                        \"--column=$($Host.UI.RawUI.CursorPosition.X)\"\n                        \"--command=$command\"\n                    )) -join ''\n                if (!$output) {\n                    return\n                }\n\n                Write-Host $output -NoNewline\n\n                # Workaround to prevent the text after cursor from disappearing when the tooltip is printed.\n                [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')\n                [Microsoft.PowerShell.PSConsoleReadLine]::Undo()\n            }\n            finally {\n            }\n        }\n    }\n\n    function Enable-KeyHandlers {\n        if ($script:ConstrainedLanguageMode) {\n            return\n        }\n\n        # Helper function to create Enter key handler script block\n        function New-EnterKeyHandler {\n            param(\n                [scriptblock]$AcceptLineFunction,\n                [hashtable]$Streaming\n            )\n            return {\n                try {\n                    $Streaming.State = 'NEW'\n                    $parseErrors = $null\n                    [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$null, [ref]$null, [ref]$parseErrors, [ref]$null)\n                    $executingCommand = $parseErrors.Count -eq 0\n                    if ($global:_ompTransientPrompt -and $executingCommand) {\n                        Set-TransientPrompt\n                    }\n                }\n                finally {\n                    & $AcceptLineFunction\n                    if ($global:_ompFTCSMarks -and $executingCommand) {\n                        # Write FTCS_COMMAND_EXECUTED after accepting the input - it should still happen before execution\n                        Write-Host \"$([char]27)]133;C$([char]7)\" -NoNewline\n                    }\n                }\n            }.GetNewClosure()\n        }\n\n        # Helper function to create Ctrl+C key handler script block\n        function New-CtrlCKeyHandler {\n            param(\n                [scriptblock]$CancelFunction,\n                [hashtable]$Streaming\n            )\n            return {\n                try {\n                    $Streaming.State = 'NEW'\n                    $start = $null\n                    [Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$start, [ref]$null)\n                    # only render a transient prompt when no text is selected\n                    if ($global:_ompTransientPrompt -and $start -eq -1) {\n                        Set-TransientPrompt\n                    }\n                }\n                finally {\n                    & $CancelFunction\n                }\n            }.GetNewClosure()\n        }\n\n        # Register Enter key handlers\n        Set-PSReadLineKeyHandler -Key Enter -BriefDescription 'OhMyPoshEnterKeyHandler' -ScriptBlock (New-EnterKeyHandler { [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() } $script:Streaming)\n\n        if ((Get-PSReadLineOption).EditMode -eq \"Vi\") {\n            Set-PSReadLineKeyHandler -ViMode Command -Key Enter -BriefDescription 'OhMyPoshViEnterKeyHandler' -ScriptBlock (New-EnterKeyHandler { [Microsoft.PowerShell.PSConsoleReadLine]::ViAcceptLine() } $script:Streaming)\n        }\n\n        # Register Ctrl+C key handlers\n        Set-PSReadLineKeyHandler -Key Ctrl+c -BriefDescription 'OhMyPoshCtrlCKeyHandler' -ScriptBlock (New-CtrlCKeyHandler { [Microsoft.PowerShell.PSConsoleReadLine]::CopyOrCancelLine() } $script:Streaming)\n\n        if ((Get-PSReadLineOption).EditMode -eq \"Vi\") {\n            Set-PSReadLineKeyHandler -ViMode Command -Key Ctrl+c -BriefDescription 'OhMyPoshViCtrlCKeyHandler' -ScriptBlock (New-CtrlCKeyHandler { [Microsoft.PowerShell.PSConsoleReadLine]::CancelLine() } $script:Streaming)\n        }\n    }\n\n    function Enable-PoshLineError {\n        $validLine = (Invoke-Utf8Posh @(\"print\", \"valid\", \"--shell=$script:ShellName\")) -join \"`n\"\n        $errorLine = (Invoke-Utf8Posh @(\"print\", \"error\", \"--shell=$script:ShellName\")) -join \"`n\"\n        Set-PSReadLineOption -PromptText $validLine, $errorLine\n    }\n\n    # perform cleanup on removal so a new initialization in current session works\n    if (!$script:ConstrainedLanguageMode) {\n        $ExecutionContext.SessionState.Module.OnRemove += {\n            # Clean up streaming process\n            Stop-StreamingProcess\n\n            Remove-Item Function:Get-PoshStackCount -ErrorAction SilentlyContinue\n\n            $Function:prompt = $script:OriginalPromptFunction\n\n            (Get-PSReadLineOption).ContinuationPrompt = $script:OriginalContinuationPrompt\n            (Get-PSReadLineOption).PromptText = $script:OriginalPromptText\n\n            if ((Get-PSReadLineKeyHandler Spacebar).Function -eq 'OhMyPoshSpaceKeyHandler') {\n                Remove-PSReadLineKeyHandler Spacebar\n            }\n\n            if ((Get-PSReadLineKeyHandler Enter).Function -eq 'OhMyPoshEnterKeyHandler') {\n                Set-PSReadLineKeyHandler Enter -Function AcceptLine\n                if ((Get-PSReadLineOption).EditMode -eq \"Vi\") {\n                    Set-PSReadLineKeyHandler -ViMode Command -Key Enter -Function ViAcceptLine\n                }\n            }\n\n            if ((Get-PSReadLineKeyHandler Ctrl+c).Function -eq 'OhMyPoshCtrlCKeyHandler') {\n                Set-PSReadLineKeyHandler Ctrl+c -Function CopyOrCancelLine\n                if ((Get-PSReadLineOption).EditMode -eq \"Vi\") {\n                    Set-PSReadLineKeyHandler -ViMode Command -Key Ctrl+c -Function CancelLine\n                }\n            }\n        }\n    }\n\n    Export-ModuleMember -Function @(\n        \"Set-PoshContext\"\n        \"Enable-PoshTooltips\"\n        \"Enable-KeyHandlers\"\n        \"Enable-PoshLineError\"\n        \"Set-TransientPrompt\"\n        \"prompt\"\n    )\n} | Import-Module -Global\n"
  },
  {
    "path": "src/shell/scripts/omp.xsh",
    "content": "$POWERLINE_COMMAND = \"oh-my-posh\"\n$POSH_SHELL = \"xonsh\"\n$POSH_SHELL_VERSION = $XONSH_VERSION\n\n# disable all known python virtual environment prompts\n$VIRTUAL_ENV_DISABLE_PROMPT = 1\n$PYENV_VIRTUALENV_DISABLE_PROMPT = 1\n\n_omp_executable = ::OMP::\n_omp_history_length = 0\n\ndef _omp_get_context():\n    global _omp_history_length\n    status = 0\n    duration = -1\n\n    if __xonsh__.history:\n        last_cmd = __xonsh__.history[-1]\n        if last_cmd:\n            status = last_cmd.rtn\n\n        history_length = len(__xonsh__.history)\n        if history_length != _omp_history_length:\n            _omp_history_length = history_length\n            duration = round((last_cmd.ts[1] - last_cmd.ts[0]) * 1000)\n\n    return status, duration\n\ndef _omp_get_prompt(type: str, *args: str):\n    status, duration = _omp_get_context()\n    return $(\n        @(_omp_executable) print @(type) \\\n            --save-cache \\\n            --shell=xonsh \\\n            --shell-version=$XONSH_VERSION \\\n            --status=@(status) \\\n            --execution-time=@(duration) \\\n            @(args)\n    )\n\ndef _omp_get_primary():\n    return _omp_get_prompt('primary')\n\ndef _omp_get_right():\n    return _omp_get_prompt('right')\n\n$PROMPT = _omp_get_primary\n# When the primary prompt has multiple lines, the right prompt is always displayed on the first line, which is inconsistent with other supported shells.\n# The behavior is controlled by Xonsh, and there is no way to change it.\n$RIGHT_PROMPT = _omp_get_right\n"
  },
  {
    "path": "src/shell/scripts/omp.zsh",
    "content": "export POSH_SHELL='zsh'\nexport POSH_SHELL_VERSION=$ZSH_VERSION\nexport POWERLINE_COMMAND='oh-my-posh'\nexport CONDA_PROMPT_MODIFIER=false\nexport ZLE_RPROMPT_INDENT=0\nexport OSTYPE=$OSTYPE\n\n# disable all known python virtual environment prompts\nexport VIRTUAL_ENV_DISABLE_PROMPT=1\nexport PYENV_VIRTUALENV_DISABLE_PROMPT=1\n\n_omp_executable=::OMP::\n_omp_tooltip_command=''\n\n# switches to enable/disable features\n_omp_cursor_positioning=0\n_omp_ftcs_marks=0\n\n# streaming support variables\n_omp_stream_fd=-1\n_omp_enable_streaming=0\n_omp_primary_prompt=\"\"\n_omp_streaming_supported=\"\"\n\n# set secondary prompt\n_omp_secondary_prompt=$($_omp_executable print secondary --shell=zsh)\n\nfunction _omp_set_cursor_position() {\n  # not supported in Midnight Commander\n  # see https://github.com/JanDeDobbeleer/oh-my-posh/issues/3415\n  if [[ $_omp_cursor_positioning == 0 ]] || [[ -v MC_SID ]]; then\n    return\n  fi\n\n  local oldstty=$(stty -g)\n  stty raw -echo min 0\n\n  local pos\n  echo -en '\\033[6n' >/dev/tty\n  read -r -d R pos\n  pos=${pos:2} # strip off the esc-[\n  local parts=(${(s:;:)pos})\n\n  stty $oldstty\n\n  export POSH_CURSOR_LINE=${parts[1]}\n  export POSH_CURSOR_COLUMN=${parts[2]}\n}\n\n# template function for context loading\nfunction set_poshcontext() {\n  return\n}\n\n# cleanup stream resources\nfunction _omp_cleanup_stream() {\n  # unregister handler first (prevents handler firing on closed fd)\n  [[ $_omp_stream_fd -ge 0 ]] && zle -F $_omp_stream_fd 2>/dev/null\n  # close fd — process gets SIGPIPE and terminates\n  [[ $_omp_stream_fd -ge 0 ]] && eval \"exec {_omp_stream_fd}<&-\" 2>/dev/null\n  _omp_stream_fd=-1\n}\n\n# start oh-my-posh stream process, block until first prompt arrives\nfunction _omp_start_streaming() {\n  # cleanup any stale streams\n  _omp_cleanup_stream\n\n  # build command with all context\n  local -a stream_cmd=(\n    \"$_omp_executable\" stream\n    --save-cache\n    --shell=zsh\n    --shell-version=\"$ZSH_VERSION\"\n    --status=$_omp_status\n    --pipestatus=\"${_omp_pipestatus[*]}\"\n    --no-status=$_omp_no_status\n    --execution-time=$_omp_execution_time\n    --job-count=$_omp_job_count\n    --stack-count=$_omp_stack_count\n    --terminal-width=\"${COLUMNS:-0}\"\n  )\n\n  # start process substitution — no PID tracking needed\n  # closing fd sends SIGPIPE which terminates oh-my-posh\n  # redirect stream process stdin to prevent it from interfering with command output\n  exec {_omp_stream_fd}< <(exec \"${stream_cmd[@]}\" </dev/null 2>/dev/null)\n\n  if [[ $_omp_stream_fd -lt 0 ]]; then\n    return 1\n  fi\n\n  # block until first prompt arrives (mirrors PowerShell's polling loop)\n  IFS= read -r -u $_omp_stream_fd -d $'\\0' _omp_primary_prompt\n  if [[ $? -ne 0 || -z \"$_omp_primary_prompt\" ]]; then\n    _omp_cleanup_stream\n    return 1\n  fi\n\n  PS1=\"$_omp_primary_prompt\"\n\n  return 0\n}\n\n# async handler: called when data available on fd (reads single value)\nfunction _omp_async_handler() {\n  local fd=$1\n\n  # read single null-delimited prompt (stream emits one value per \\0)\n  IFS= read -r -u $fd -d $'\\0' _omp_primary_prompt\n  if [[ $? -ne 0 ]]; then\n    if [[ -z \"$_omp_primary_prompt\" ]]; then\n      # EOF — stream closed normally\n      _omp_cleanup_stream\n      return 0\n    fi\n  fi\n\n  PS1=\"$_omp_primary_prompt\"\n  zle reset-prompt 2>/dev/null\n\n  return 0\n}\n\n# shell exit handler\nfunction _omp_exit_handler() {\n  _omp_cleanup_stream\n}\n\n# register exit handler\nzshexit_functions+=(_omp_exit_handler)\n\nfunction _omp_preexec() {\n  if [[ $_omp_ftcs_marks == 1 ]]; then\n    printf '\\033]133;C\\007'\n  fi\n\n  _omp_start_time=$($_omp_executable get millis)\n}\n\nfunction _omp_precmd() {\n  _omp_status=$?\n  _omp_pipestatus=(${pipestatus[@]})\n  _omp_job_count=${#jobstates}\n  _omp_stack_count=${#dirstack[@]}\n  _omp_execution_time=-1\n  _omp_no_status=true\n  _omp_tooltip_command=''\n\n  if [[ -n $_omp_start_time ]]; then\n    local omp_now=$($_omp_executable get millis)\n    _omp_execution_time=$(($omp_now - $_omp_start_time))\n    _omp_no_status=false\n  fi\n\n  if [[ ${_omp_pipestatus[-1]} != \"$_omp_status\" ]]; then\n    _omp_pipestatus=(\"$_omp_status\")\n  fi\n\n  set_poshcontext\n  _omp_set_cursor_position\n\n  # We do this to avoid unexpected expansions in a prompt string.\n  unsetopt PROMPT_SUBST\n  unsetopt PROMPT_BANG\n\n  # Ensure that escape sequences work in a prompt string.\n  setopt PROMPT_PERCENT\n\n  PS2=$_omp_secondary_prompt\n\n  # === STREAMING PATH ===\n  if [[ $_omp_enable_streaming -eq 1 ]]; then\n    # set RPROMPT synchronously (stream only emits primary prompt)\n    RPROMPT=$(_omp_get_prompt right)\n\n    # start new streaming session (blocks until first prompt arrives)\n    if _omp_start_streaming; then\n      # PS1 already set by _omp_start_streaming (blocking first read)\n      zle -F $_omp_stream_fd _omp_async_handler\n      unset _omp_start_time\n      return 0\n    fi\n    # fall through to sync\n  fi\n\n  # === FALLBACK PATH ===\n  eval \"$(_omp_get_prompt primary --eval)\"\n\n  unset _omp_start_time\n}\n\n# add hook functions\nautoload -Uz add-zsh-hook\nadd-zsh-hook precmd _omp_precmd\nadd-zsh-hook preexec _omp_preexec\n\n# Prevent incorrect behaviors when the initialization is executed twice in current session.\nfunction _omp_cleanup() {\n  local omp_widgets=(\n    self-insert\n    zle-line-init\n  )\n  local widget\n  for widget in \"${omp_widgets[@]}\"; do\n    if [[ ${widgets[._omp_original::$widget]} ]]; then\n      # Restore the original widget.\n      zle -A ._omp_original::$widget $widget\n    elif [[ ${widgets[$widget]} = user:_omp_* ]]; then\n      # Delete the OMP-defined widget.\n      zle -D $widget\n    fi\n  done\n}\n_omp_cleanup\nunset -f _omp_cleanup\n\nfunction _omp_get_prompt() {\n  local type=$1\n  local args=(\"${@[2,-1]}\")\n  $_omp_executable print $type \\\n    --save-cache \\\n    --shell=zsh \\\n    --shell-version=$ZSH_VERSION \\\n    --status=$_omp_status \\\n    --pipestatus=\"${_omp_pipestatus[*]}\" \\\n    --no-status=$_omp_no_status \\\n    --execution-time=$_omp_execution_time \\\n    --job-count=$_omp_job_count \\\n    --stack-count=$_omp_stack_count \\\n    --terminal-width=\"${COLUMNS-0}\" \\\n    ${args[@]}\n}\n\nfunction _omp_render_tooltip() {\n  if [[ $KEYS != ' ' ]]; then\n    return\n  fi\n\n  setopt local_options no_shwordsplit\n\n  # Get the first word of command line as tip.\n  local tooltip_command=${${(MS)BUFFER##[[:graph:]]*}%%[[:space:]]*}\n\n  # Ignore an empty/repeated tooltip command.\n  if [[ -z $tooltip_command ]] || [[ $tooltip_command = \"$_omp_tooltip_command\" ]]; then\n    return\n  fi\n\n  _omp_tooltip_command=\"$tooltip_command\"\n  local tooltip=$(_omp_get_prompt tooltip --command=\"$tooltip_command\")\n  if [[ -z $tooltip ]]; then\n    return\n  fi\n\n  RPROMPT=$tooltip\n  zle .reset-prompt\n}\n\nfunction _omp_zle-line-init() {\n  [[ $CONTEXT == start ]] || return 0\n\n  # Start regular line editor.\n  (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[1]\n  zle .recursive-edit\n  local -i ret=$?\n  (( $+zle_bracketed_paste )) && print -r -n - $zle_bracketed_paste[2]\n\n  # We need this workaround because when the `filler` is set,\n  # there will be a redundant blank line below the transient prompt if the input is empty.\n  local terminal_width_option\n  if [[ -z $BUFFER ]]; then\n    terminal_width_option=\"--terminal-width=$((${COLUMNS-0} - 1))\"\n  fi\n\n  # kill streaming before transient prompt to prevent handler overwriting it\n  _omp_cleanup_stream\n\n  eval \"$(_omp_get_prompt transient --eval $terminal_width_option)\"\n  zle .reset-prompt\n\n  if ((ret)); then\n    # TODO (fix): this is not equal to sending a SIGINT, since the status code ($?) is set to 1 instead of 130.\n    zle .send-break\n  fi\n\n  # Exit the shell if we receive EOT.\n  if [[ $KEYS == $'\\4' ]]; then\n    exit\n  fi\n\n  zle .accept-line\n  return $ret\n}\n\n# Helper function for calling a widget before the specified OMP function.\nfunction _omp_call_widget() {\n  # The name of the OMP function.\n  local omp_func=$1\n  # The remainder are the widget to call and potential arguments.\n  shift\n\n  zle \"$@\" && shift 2 && $omp_func \"$@\"\n}\n\n# Create a widget with the specified OMP function.\n# An existing widget will be preserved and decorated with the function.\nfunction _omp_create_widget() {\n  # The name of the widget to create/decorate.\n  local widget=$1\n  # The name of the OMP function.\n  local omp_func=$2\n\n  case ${widgets[$widget]:-''} in\n  # Already decorated: do nothing.\n  user:_omp_decorated_*) ;;\n\n  # Non-existent: just create it.\n  '')\n    zle -N $widget $omp_func\n    ;;\n\n  # User-defined or builtin: backup and decorate it.\n  *)\n    # Back up the original widget. The leading dot in widget name is to work around bugs when used with zsh-syntax-highlighting in Zsh v5.8 or lower.\n    zle -A $widget ._omp_original::$widget\n    eval \"_omp_decorated_${(q)widget}() { _omp_call_widget ${(q)omp_func} ._omp_original::${(q)widget} -- \\\"\\$@\\\" }\"\n    zle -N $widget _omp_decorated_$widget\n    ;;\n  esac\n}\n\nfunction enable_poshtooltips() {\n  local widget=${$(bindkey ' '):2}\n\n  if [[ -z $widget ]]; then\n    widget=self-insert\n  fi\n\n  _omp_create_widget $widget _omp_render_tooltip\n}\n\n# legacy functions\nfunction enable_poshtransientprompt() {}\n"
  },
  {
    "path": "src/shell/xonsh.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed scripts/omp.xsh\nvar xonshInit string\n\nfunc (f Features) Xonsh() Code {\n\tswitch f {\n\tcase Upgrade:\n\t\treturn \"@(_omp_executable) upgrade --auto\"\n\tcase Notice:\n\t\treturn \"@(_omp_executable) notice\"\n\tcase PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Tooltips, Transient, CursorPositioning, FTCSMarks, Async, Streaming, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n\nfunc quotePythonStr(str string) string {\n\tif str == \"\" {\n\t\treturn \"''\"\n\t}\n\n\treturn fmt.Sprintf(\"'%s'\", strings.NewReplacer(\n\t\t\"'\", `'\"'\"'`,\n\t\t`\\`, `\\\\`,\n\t\t\"\\n\", `\\n`,\n\t).Replace(str))\n}\n"
  },
  {
    "path": "src/shell/xonsh_test.go",
    "content": "package shell\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestXonshFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(XONSH).String(\"// these are the features\")\n\n\twant := `// these are the features\n@(_omp_executable) upgrade --auto\n@(_omp_executable) notice`\n\n\tassert.Equal(t, want, got)\n}\n\nfunc TestQuotePythonStr(t *testing.T) {\n\ttests := []struct {\n\t\tstr      string\n\t\texpected string\n\t}{\n\t\t{str: \"\", expected: \"''\"},\n\t\t{str: `/tmp/\"omp's dir\"/oh-my-posh`, expected: `'/tmp/\"omp'\"'\"'s dir\"/oh-my-posh'`},\n\t\t{str: `C:/tmp\\omp's dir/oh-my-posh.exe`, expected: `'C:/tmp\\\\omp'\"'\"'s dir/oh-my-posh.exe'`},\n\t}\n\tfor _, tc := range tests {\n\t\tassert.Equal(t, tc.expected, quotePythonStr(tc.str), fmt.Sprintf(\"quotePythonStr: %s\", tc.str))\n\t}\n}\n"
  },
  {
    "path": "src/shell/zsh.go",
    "content": "package shell\n\nimport (\n\t_ \"embed\"\n)\n\n//go:embed scripts/omp.zsh\nvar zshInit string\n\nfunc (f Features) Zsh() Code {\n\tswitch f {\n\tcase CursorPositioning:\n\t\treturn unixCursorPositioning\n\tcase Tooltips:\n\t\treturn \"enable_poshtooltips\"\n\tcase Transient:\n\t\treturn \"_omp_create_widget zle-line-init _omp_zle-line-init\"\n\tcase FTCSMarks:\n\t\treturn unixFTCSMarks\n\tcase Upgrade:\n\t\treturn unixUpgrade\n\tcase Notice:\n\t\treturn unixNotice\n\tcase Streaming:\n\t\treturn \"_omp_enable_streaming=1\"\n\tcase PromptMark, RPrompt, PoshGit, Azure, LineError, Jobs, Async, KeyHandlers:\n\t\tfallthrough\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "src/shell/zsh_test.go",
    "content": "package shell\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestZshFeatures(t *testing.T) {\n\tgot := allFeatures.Lines(ZSH).String(\"// these are the features\")\n\n\twant := `// these are the features\nenable_poshtooltips\n_omp_create_widget zle-line-init _omp_zle-line-init\n_omp_ftcs_marks=1\n\"$_omp_executable\" upgrade --auto\n\"$_omp_executable\" notice\n_omp_cursor_positioning=1\n_omp_enable_streaming=1`\n\n\tassert.Equal(t, want, got)\n}\n"
  },
  {
    "path": "src/template/cache.go",
    "content": "package template\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/build\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/path\"\n)\n\nvar (\n\tCache *cache.Template\n)\n\nfunc loadCache(vars maps.Simple[any], aliases *maps.Config) {\n\tif !env.Flags().IsPrimary {\n\t\t// Load the template cache for a non-primary prompt before rendering any templates.\n\t\tif OK := restoreCache(); OK {\n\t\t\treturn\n\t\t}\n\t}\n\n\tCache = new(cache.Template)\n\n\tCache.Root = env.Root()\n\tCache.Shell = aliases.GetShellName(env.Shell())\n\tCache.ShellVersion = env.Flags().ShellVersion\n\tCache.Code, _ = env.StatusCodes()\n\tCache.WSL = env.IsWsl()\n\tCache.Segments = maps.NewConcurrent[any]()\n\tCache.PromptCount = env.Flags().PromptCount\n\tCache.Var = make(map[string]any)\n\tCache.Jobs = env.Flags().JobCount\n\tCache.Version = build.Version\n\n\tif vars != nil {\n\t\tCache.Var = vars\n\t}\n\n\tpwd := env.Pwd()\n\tCache.PWD = path.ReplaceHomeDirPrefixWithTilde(pwd)\n\n\tCache.AbsolutePWD = pwd\n\tif env.IsWsl() {\n\t\tCache.AbsolutePWD, _ = env.RunCommand(\"wslpath\", \"-m\", pwd)\n\t}\n\n\tenv.Flags().AbsolutePWD = Cache.AbsolutePWD\n\tCache.PSWD = env.Flags().PSWD\n\n\tCache.Folder = path.Base(pwd)\n\tif env.GOOS() == runtime.WINDOWS && strings.HasSuffix(Cache.Folder, \":\") {\n\t\tCache.Folder += `\\`\n\t}\n\n\tCache.UserName = aliases.GetUserName(env.User())\n\tif host, err := env.Host(); err == nil {\n\t\tCache.HostName = aliases.GetHostName(host)\n\t}\n\n\tgoos := env.GOOS()\n\tCache.OS = goos\n\tif goos == runtime.LINUX {\n\t\tCache.OS = env.Platform()\n\t}\n\n\tval := env.Getenv(\"SHLVL\")\n\tif shlvl, err := strconv.Atoi(val); err == nil {\n\t\tCache.SHLVL = shlvl\n\t}\n}\n\nfunc restoreCache() bool {\n\tdefer log.Trace(time.Now())\n\n\tval, OK := cache.Get[cache.SimpleTemplate](cache.Session, cache.TEMPLATECACHE)\n\tif !OK {\n\t\treturn false\n\t}\n\n\tCache = new(cache.Template)\n\tCache.SimpleTemplate = val\n\tCache.Segments = Cache.SegmentsCache.ToConcurrent()\n\n\treturn true\n}\n\nfunc SaveCache() {\n\t// only store this when in a primary prompt\n\t// and when we have any extra prompt in the config\n\tcanSave := env.Flags().IsPrimary && env.Flags().HasExtra\n\tif !canSave {\n\t\treturn\n\t}\n\n\tCache.SegmentsCache = Cache.Segments.ToSimple()\n\n\tcache.Set(cache.Session, cache.TEMPLATECACHE, &Cache.SimpleTemplate, cache.ONEDAY)\n}\n"
  },
  {
    "path": "src/template/compare.go",
    "content": "package template\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n\nfunc toIntOrZero(e any) int {\n\tif value, err := generics.TryParseInt[int](e); err == nil {\n\t\treturn value\n\t}\n\n\treturn 0\n}\n\nfunc toInt(integer any) (int, error) {\n\treturn generics.TryParseInt[int](integer)\n}\n\nfunc toFloat64(e any) float64 {\n\tif val, err := generics.TryParseFloat[float64](e); err == nil {\n\t\treturn val\n\t}\n\treturn 0\n}\n\nfunc gt(e1, e2 any) bool {\n\tif val, OK := e1.(int); OK {\n\t\treturn val > toIntOrZero(e2)\n\t}\n\tif val, OK := e1.(int64); OK {\n\t\treturn val > int64(toIntOrZero(e2))\n\t}\n\tif val, OK := e1.(float64); OK {\n\t\treturn val > toFloat64(e2)\n\t}\n\treturn false\n}\n\nfunc lt(e1, e2 any) bool {\n\treturn gt(e2, e1)\n}\n"
  },
  {
    "path": "src/template/compare_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGt(t *testing.T) {\n\tcases := []struct {\n\t\tE1       any\n\t\tE2       any\n\t\tCase     string\n\t\tExpected bool\n\t}{\n\t\t{Case: \"Float vs int\", Expected: false, E1: float64(3), E2: 4},\n\t\t{Case: \"Int vs float\", Expected: false, E1: 3, E2: float64(4)},\n\t\t{Case: \"Int vs Int\", Expected: false, E1: 3, E2: 4},\n\t\t{Case: \"Int64 vs Int\", Expected: false, E1: int64(3), E2: 4},\n\t\t{Case: \"Float vs Float\", Expected: false, E1: float64(3), E2: float64(4)},\n\t\t{Case: \"Float vs String\", Expected: true, E1: float64(3), E2: \"test\"},\n\t\t{Case: \"Int vs String\", Expected: true, E1: 3, E2: \"test\"},\n\t\t{Case: \"String vs String\", Expected: false, E1: \"test\", E2: \"test\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tgot := gt(tc.E1, tc.E2)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestLt(t *testing.T) {\n\tcases := []struct {\n\t\tE1       any\n\t\tE2       any\n\t\tCase     string\n\t\tExpected bool\n\t}{\n\t\t{Case: \"Float vs int\", Expected: true, E1: float64(3), E2: 4},\n\t\t{Case: \"Int vs float\", Expected: true, E1: 3, E2: float64(4)},\n\t\t{Case: \"Int vs Int\", Expected: true, E1: 3, E2: 4},\n\t\t{Case: \"Float vs Float\", Expected: true, E1: float64(3), E2: float64(4)},\n\t\t{Case: \"Float vs String\", Expected: false, E1: float64(3), E2: \"test\"},\n\t\t{Case: \"String vs String\", Expected: false, E1: \"test\", E2: \"test\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tgot := lt(tc.E1, tc.E2)\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/template/files.go",
    "content": "package template\n\nimport (\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\nfunc glob(pattern string) (bool, error) {\n\tmatches, err := filepath.Glob(pattern)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\treturn len(matches) > 0, nil\n}\n\nfunc readFile(path string) string {\n\tcontent, _ := os.ReadFile(path)\n\treturn string(content)\n}\n\nfunc stat(path string) string {\n\tfullPath, err := exec.LookPath(path)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\"\n\t}\n\n\treturn fullPath\n}\n"
  },
  {
    "path": "src/template/files_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGlob(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{Case: \"valid glob\", Expected: \"OK\", Template: `{{ if glob \"*.go\" }}OK{{ else }}NOK{{ end }}`},\n\t\t{Case: \"invalid glob\", Expected: \"NOK\", Template: `{{ if glob \"package.json\" }}OK{{ else }}NOK{{ end }}`},\n\t\t{Case: \"multiple glob\", Expected: \"NOK\", Template: `{{ if or (glob \"package.json\") (glob \"node_modules\") }}OK{{ else }}NOK{{ end }}`},\n\t}\n\n\tenv := &mock.Environment{}\n\tenv.On(\"Shell\").Return(\"foo\")\n\n\tCache = new(cache.Template)\n\tInit(env, nil, nil)\n\n\tfor _, tc := range cases {\n\t\ttext, err := Render(tc.Template, nil)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/template/func_map.go",
    "content": "package template\n\nimport (\n\t\"path/filepath\"\n\t\"text/template\"\n\n\t\"github.com/Masterminds/sprig/v3\"\n)\n\nfunc funcMap() template.FuncMap {\n\tfuncMap := map[string]any{\n\t\t\"secondsRound\": secondsRound,\n\t\t\"url\":          url,\n\t\t\"path\":         filePath,\n\t\t\"glob\":         glob,\n\t\t\"matchP\":       matchP,\n\t\t\"findP\":        findP,\n\t\t\"replaceP\":     replaceP,\n\t\t\"gt\":           gt,\n\t\t\"lt\":           lt,\n\t\t\"random\":       random,\n\t\t\"reason\":       GetReasonFromStatus,\n\t\t\"hresult\":      hresult,\n\t\t\"trunc\":        trunc,\n\t\t\"truncE\":       TruncE,\n\t\t\"readFile\":     readFile,\n\t\t\"stat\":         stat,\n\t\t\"dir\":          filepath.Dir,\n\t\t\"base\":         filepath.Base,\n\t}\n\n\tfor key, fun := range sprig.TxtFuncMap() {\n\t\tif _, ok := funcMap[key]; !ok {\n\t\t\tfuncMap[key] = fun\n\t\t}\n\t}\n\n\treturn template.FuncMap(funcMap)\n}\n"
  },
  {
    "path": "src/template/init.go",
    "content": "package template\n\nimport (\n\t\"sync\"\n\t\"text/template\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime\"\n)\n\nconst (\n\t// Errors to show when the template handling fails\n\tInvalidTemplate   = \"invalid template text\"\n\tIncorrectTemplate = \"unable to create text based on template\"\n\n\tglobalRef = \".$\"\n\n\telvish = \"elvish\"\n\txonsh  = \"xonsh\"\n)\n\nvar (\n\tshell       string\n\tenv         runtime.Environment\n\tknownFields sync.Map\n\ttextPool    *generics.Pool[*Text]\n)\n\nfunc Init(environment runtime.Environment, vars maps.Simple[any], aliases *maps.Config) {\n\tenv = environment\n\tshell = env.Shell()\n\tknownFields = sync.Map{}\n\n\trenderPool = generics.NewPool(func() *renderer {\n\t\treturn &renderer{\n\t\t\ttemplate: template.New(\"cache\").Funcs(funcMap()),\n\t\t\tcontext:  &context{},\n\t\t}\n\t})\n\n\ttextPool = generics.NewPool(func() *Text {\n\t\treturn &Text{}\n\t})\n\n\tif Cache != nil {\n\t\treturn\n\t}\n\n\tloadCache(vars, aliases)\n}\n"
  },
  {
    "path": "src/template/link.go",
    "content": "package template\n\nimport (\n\t\"fmt\"\n\tlink \"net/url\"\n\t\"slices\"\n)\n\n// url builds a hyperlink if url is not empty, otherwise returns the text only\nfunc url(text, url string) (string, error) {\n\tunsupported := []string{elvish, xonsh}\n\tif slices.Contains(unsupported, shell) {\n\t\treturn text, nil\n\t}\n\n\tif url == \"\" {\n\t\treturn text, nil\n\t}\n\t_, err := link.ParseRequestURI(url)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn fmt.Sprintf(\"<LINK>%s<TEXT>%s</TEXT></LINK>\", url, text), nil\n}\n\nfunc filePath(text, path string) (string, error) {\n\tunsupported := []string{elvish, xonsh}\n\tif slices.Contains(unsupported, shell) {\n\t\treturn text, nil\n\t}\n\n\treturn fmt.Sprintf(\"<LINK>file:%s<TEXT>%s</TEXT></LINK>\", path, text), nil\n}\n"
  },
  {
    "path": "src/template/link_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestUrl(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{Case: \"valid url\", Expected: \"<LINK>https://ohmyposh.dev<TEXT>link</TEXT></LINK>\", Template: `{{ url \"link\" \"https://ohmyposh.dev\" }}`},\n\t\t{Case: \"invalid url\", Expected: \"\", Template: `{{ url \"link\" \"Foo\" }}`, ShouldError: true},\n\t}\n\n\tenv := &mock.Environment{}\n\tenv.On(\"Shell\").Return(\"foo\")\n\n\tCache = new(cache.Template)\n\n\tInit(env, nil, nil)\n\n\tfor _, tc := range cases {\n\t\ttext, err := Render(tc.Template, nil)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n\nfunc TestPath(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{Case: \"valid path\", Expected: \"<LINK>file:/test/test<TEXT>link</TEXT></LINK>\", Template: `{{ path \"link\" \"/test/test\" }}`},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttext, _ := Render(tc.Template, nil)\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/template/list.go",
    "content": "package template\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\ntype Logic string\n\nconst (\n\tFirstMatch Logic = \"first_match\"\n\tJoin       Logic = \"join\"\n)\n\ntype List []string\n\nfunc (l List) Empty() bool {\n\treturn len(l) == 0\n}\n\nfunc (l List) Resolve(context any, defaultValue string, logic Logic) string {\n\tif l.Empty() {\n\t\treturn defaultValue\n\t}\n\n\tswitch logic {\n\tcase FirstMatch:\n\t\treturn l.FirstMatch(context, defaultValue)\n\tcase Join:\n\t\tfallthrough\n\tdefault:\n\t\treturn l.Join(context)\n\t}\n}\n\nfunc (l List) Join(context any) string {\n\tif len(l) == 0 {\n\t\treturn \"\"\n\t}\n\n\tbuffer := text.NewBuilder()\n\n\tfor _, tmpl := range l {\n\t\tvalue, err := Render(tmpl, context)\n\t\tif err != nil || len(strings.TrimSpace(value)) == 0 {\n\t\t\tcontinue\n\t\t}\n\n\t\tbuffer.WriteString(value)\n\t}\n\n\treturn buffer.String()\n}\n\nfunc (l List) FirstMatch(context any, defaultValue string) string {\n\tif len(l) == 0 {\n\t\treturn defaultValue\n\t}\n\n\tfor _, tmpl := range l {\n\t\tvalue, err := Render(tmpl, context)\n\t\tif err != nil || len(strings.TrimSpace(value)) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\treturn value\n\t}\n\n\treturn defaultValue\n}\n"
  },
  {
    "path": "src/template/numbers.go",
    "content": "package template\n\nimport \"fmt\"\n\nfunc hresult(number int) string {\n\treturn fmt.Sprintf(\"0x%04X\", uint32(number))\n}\n"
  },
  {
    "path": "src/template/numbers_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestHResult(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{Case: \"Windows exit code\", Expected: \"0x8A150014\", Template: `{{ hresult -1978335212 }}`},\n\t\t{Case: \"Not a number\", Template: `{{ hresult \"no number\" }}`, ShouldError: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttext, err := Render(tc.Template, nil)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/template/pool_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTextPool(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(\"foo\")\n\tCache = new(cache.Template)\n\tInit(env, nil, nil)\n\n\t// Test rendering\n\tresult, err := Render(\"Hello {{ .Name }}\", map[string]any{\"Name\": \"World\"})\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"Hello World\", result)\n\n\t// Test empty template\n\tresult2, err := Render(\"\", nil)\n\tassert.NoError(t, err)\n\tassert.Equal(t, \"\", result2)\n}\n"
  },
  {
    "path": "src/template/random.go",
    "content": "package template\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand/v2\"\n\t\"reflect\"\n)\n\nfunc random(list any) (string, error) {\n\tv := reflect.ValueOf(list)\n\n\tif v.Kind() != reflect.Slice && v.Kind() != reflect.Array {\n\t\treturn \"\", errors.New(\"input must be a slice or array\")\n\t}\n\n\tif v.Len() == 0 {\n\t\treturn \"\", errors.New(\"input slice or array is empty\")\n\t}\n\n\treturn fmt.Sprintf(\"%v\", v.Index(rand.IntN(v.Len()))), nil\n}\n"
  },
  {
    "path": "src/template/random_test.go",
    "content": "package template\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRandom(t *testing.T) {\n\tcases := []struct {\n\t\tInput       any\n\t\tCase        string\n\t\tShouldError bool\n\t}{\n\t\t{\n\t\t\tCase:  \"valid slice\",\n\t\t\tInput: []int{1, 2, 3, 4, 5},\n\t\t},\n\t\t{\n\t\t\tCase:  \"valid array\",\n\t\t\tInput: [5]int{1, 2, 3, 4, 5},\n\t\t},\n\t\t{\n\t\t\tCase:        \"empty slice\",\n\t\t\tInput:       []int{},\n\t\t\tShouldError: true,\n\t\t},\n\t\t{\n\t\t\tCase:        \"not a slice or array\",\n\t\t\tInput:       \"not a slice\",\n\t\t\tShouldError: true,\n\t\t},\n\t\t{\n\t\t\tCase:  \"valid string slice\",\n\t\t\tInput: []string{\"a\", \"b\", \"c\"},\n\t\t},\n\t\t{\n\t\t\tCase:  \"valid float slice\",\n\t\t\tInput: []float64{1.1, 2.2, 3.3},\n\t\t},\n\t\t{\n\t\t\tCase: \"interface with multiple types\",\n\t\t\tInput: []any{\n\t\t\t\t\"a\",\n\t\t\t\t1,\n\t\t\t\ttrue,\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:  \"valid struct slice\",\n\t\t\tInput: []struct{ Name string }{{Name: \"Alice\"}, {Name: \"Bob\"}},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tresult, err := random(tc.Input)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err, tc.Case)\n\t\t} else {\n\t\t\tassert.NoError(t, err, tc.Case)\n\t\t\tassert.Contains(t, fmt.Sprintf(\"%v\", tc.Input), result, tc.Case)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/template/reason.go",
    "content": "package template\n\nimport \"strconv\"\n\nfunc GetReasonFromStatus(code int) string { //nolint: gocyclo\n\tswitch code {\n\tcase 1:\n\t\treturn \"ERROR\"\n\tcase 2, 64:\n\t\treturn \"USAGE\"\n\tcase 65:\n\t\treturn \"DATAERR\"\n\tcase 66:\n\t\treturn \"NOINPUT\"\n\tcase 67:\n\t\treturn \"NOUSER\"\n\tcase 68:\n\t\treturn \"NOHOST\"\n\tcase 69:\n\t\treturn \"UNAVAILABLE\"\n\tcase 70:\n\t\treturn \"SOFTWARE\"\n\tcase 71:\n\t\treturn \"OSERR\"\n\tcase 72:\n\t\treturn \"OSFILE\"\n\tcase 73:\n\t\treturn \"CANTCREAT\"\n\tcase 74:\n\t\treturn \"IOERR\"\n\tcase 75:\n\t\treturn \"TEMPFAIL\"\n\tcase 76:\n\t\treturn \"PROTOCOL\"\n\tcase 77, 126:\n\t\treturn \"NOPERM\"\n\tcase 78:\n\t\treturn \"CONFIG\"\n\tcase 127:\n\t\treturn \"NOTFOUND\"\n\tcase 128 + 1:\n\t\treturn \"SIGHUP\"\n\tcase 128 + 2:\n\t\treturn \"SIGINT\"\n\tcase 128 + 3:\n\t\treturn \"SIGQUIT\"\n\tcase 128 + 4:\n\t\treturn \"SIGILL\"\n\tcase 128 + 5:\n\t\treturn \"SIGTRAP\"\n\tcase 128 + 6:\n\t\treturn \"SIGIOT\"\n\tcase 128 + 7:\n\t\treturn \"SIGBUS\"\n\tcase 128 + 8:\n\t\treturn \"SIGFPE\"\n\tcase 128 + 9:\n\t\treturn \"SIGKILL\"\n\tcase 128 + 10:\n\t\treturn \"SIGUSR1\"\n\tcase 128 + 11:\n\t\treturn \"SIGSEGV\"\n\tcase 128 + 12:\n\t\treturn \"SIGUSR2\"\n\tcase 128 + 13:\n\t\treturn \"SIGPIPE\"\n\tcase 128 + 14:\n\t\treturn \"SIGALRM\"\n\tcase 128 + 15:\n\t\treturn \"SIGTERM\"\n\tcase 128 + 16:\n\t\treturn \"SIGSTKFLT\"\n\tcase 128 + 17:\n\t\treturn \"SIGCHLD\"\n\tcase 128 + 18:\n\t\treturn \"SIGCONT\"\n\tcase 128 + 19:\n\t\treturn \"SIGSTOP\"\n\tcase 128 + 20:\n\t\treturn \"SIGTSTP\"\n\tcase 128 + 21:\n\t\treturn \"SIGTTIN\"\n\tcase 128 + 22:\n\t\treturn \"SIGTTOU\"\n\tdefault:\n\t\treturn strconv.Itoa(code)\n\t}\n}\n"
  },
  {
    "path": "src/template/regex.go",
    "content": "package template\n\nimport \"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\nfunc matchP(pattern, text string) bool {\n\treturn regex.MatchString(pattern, text)\n}\n\nfunc replaceP(pattern, text, replaceText string) string {\n\treturn regex.ReplaceAllString(pattern, text, replaceText)\n}\n\nfunc findP(pattern, text string, index int) string {\n\tmatch, _ := regex.FindStringMatch(pattern, text, index)\n\treturn match\n}\n"
  },
  {
    "path": "src/template/render.go",
    "content": "package template\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Data any\n\ntype context struct {\n\tData\n\tGetenv func(string) string\n\tcache.Template\n}\n\nfunc (c *context) init(t *Text) {\n\tc.Data = t.context\n\tc.Getenv = env.Getenv\n\tc.Template = *Cache\n}\n\nvar (\n\trenderPool *generics.Pool[*renderer]\n)\n\ntype renderer struct {\n\ttemplate *template.Template\n\tcontext  *context\n\tbuffer   bytes.Buffer\n}\n\nfunc (t *renderer) release() {\n\tt.buffer.Reset()\n\tt.context.Data = nil\n\tt.template.New(\"cache\")\n\trenderPool.Put(t)\n}\n\nfunc (t *renderer) execute(text *Text) (string, error) {\n\ttmpl, err := t.template.Parse(text.template)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", errors.New(InvalidTemplate)\n\t}\n\n\tt.context.init(text)\n\n\terr = tmpl.Execute(&t.buffer, t.context)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\treturn \"\", errors.New(IncorrectTemplate)\n\t}\n\n\toutput := t.buffer.String()\n\n\t// issue with missingkey=zero ignored for map[string]any\n\t// https://github.com/golang/go/issues/24963\n\toutput = strings.ReplaceAll(output, \"<no value>\", \"\")\n\n\treturn output, nil\n}\n"
  },
  {
    "path": "src/template/round.go",
    "content": "package template\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nfunc secondsRound(seconds any) string {\n\ts, err := toInt(seconds)\n\tif err != nil {\n\t\treturn err.Error()\n\t}\n\tif s == 0 {\n\t\treturn \"0s\"\n\t}\n\tneg := s < 0\n\tif neg {\n\t\ts = -s\n\t}\n\n\tvar (\n\t\tsecond = 1\n\t\tminute = 60\n\t\thour   = 3600\n\t\tday    = 86400\n\t\tmonth  = 2629800\n\t\tyear   = 31560000\n\t)\n\tbuilder := text.NewBuilder()\n\n\twritePart := func(unit int, name string) {\n\t\tif s >= unit {\n\t\t\tbuilder.WriteString(\" \")\n\t\t\tbuilder.WriteString(strconv.Itoa(s / unit))\n\t\t\tbuilder.WriteString(name)\n\t\t\ts %= unit\n\t\t}\n\t}\n\twritePart(year, \"y\")\n\twritePart(month, \"mo\")\n\twritePart(day, \"d\")\n\twritePart(hour, \"h\")\n\twritePart(minute, \"m\")\n\twritePart(second, \"s\")\n\treturn strings.Trim(builder.String(), \" \")\n}\n"
  },
  {
    "path": "src/template/round_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRoundSeconds(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{Case: \"int - 1 second\", Expected: \"1s\", Template: \"{{ secondsRound 1 }}\"},\n\t\t{Case: \"double - 1 second\", Expected: \"1s\", Template: \"{{ secondsRound 1.1 }}\"},\n\t\t{Case: \"int - 1 minute\", Expected: \"1m\", Template: \"{{ secondsRound 60 }}\"},\n\t\t{Case: \"int - 2 minutes 30 seconds\", Expected: \"2m 30s\", Template: \"{{ secondsRound 150 }}\"},\n\t\t{Case: \"int - 1 day 2 minutes 30 seconds\", Expected: \"1d 2m 30s\", Template: \"{{ secondsRound 86550 }}\"},\n\t\t{Case: \"double - 1 day 2 minutes 30 seconds\", Expected: \"1d 2m 30s\", Template: \"{{ secondsRound 86550.555 }}\"},\n\t\t{Case: \"int - 1 month 1 day 2 minutes 30 seconds\", Expected: \"1mo 1d 2m 30s\", Template: \"{{ secondsRound 2716350 }}\"},\n\t\t{Case: \"int - 1 year 1 month 1 day 2 minutes 30 seconds\", Expected: \"1y 1mo 1d 2m 30s\", Template: \"{{ secondsRound 34276350 }}\"},\n\t\t{Case: \"error\", Expected: \"\", Template: \"{{ secondsRound foo }}\", ShouldError: true},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttext, err := Render(tc.Template, nil)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/template/strings.go",
    "content": "package template\n\nimport (\n\t\"unicode/utf8\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n)\n\nfunc trunc(length any, s string) string {\n\tc, err := generics.TryParseInt[int](length)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\trunes := []rune(s)\n\tif len(runes) <= c {\n\t\treturn s\n\t}\n\n\tif c < 0 {\n\t\treturn string(runes[len(runes)+c:])\n\t}\n\n\treturn string(runes[0:c])\n}\n\nfunc TruncE(length any, s string) string {\n\tc, err := generics.TryParseInt[int](length)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\ttruncateSymbol := \"…\"\n\n\tif c == 0 {\n\t\treturn truncateSymbol\n\t}\n\n\tlenTruncateSymbol := utf8.RuneCountInString(truncateSymbol)\n\tif c < 0 {\n\t\tlenTruncateSymbol *= -1\n\t}\n\tc -= lenTruncateSymbol\n\n\trunes := []rune(s)\n\tif len(runes) <= c {\n\t\treturn s\n\t}\n\n\tif c < 0 {\n\t\treturn truncateSymbol + string(runes[len(runes)+c:])\n\t}\n\n\treturn string(runes[0:c]) + truncateSymbol\n}\n"
  },
  {
    "path": "src/template/strings_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestTrunc(t *testing.T) {\n\tcases := []struct {\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{Case: \"5 length integer\", Expected: \"Hello\", Template: `{{ trunc 5 \"Hello World\" }}`},\n\t\t{Case: \"5 length stringteger\", Expected: \"Hello\", Template: `{{ trunc \"5\" \"Hello World\" }}`},\n\t\t{Case: \"5 length float\", Expected: \"Hello\", Template: `{{ trunc 5.0 \"Hello World\" }}`},\n\t\t{Case: \"invalid\", ShouldError: true, Template: `{{ trunc \"foo\" \"Hello World\" }}`},\n\t\t{Case: \"smaller than length\", Expected: \"Hello World\", Template: `{{ trunc 20 \"Hello World\" }}`},\n\t\t{Case: \"negative\", Expected: \"ld\", Template: `{{ trunc -2 \"Hello World\" }}`},\n\t}\n\n\tfor _, tc := range cases {\n\t\ttext, err := Render(tc.Template, nil)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n\nfunc TestTruncE(t *testing.T) {\n\tcases := []struct {\n\t\tname      string\n\t\tlength    any\n\t\tinput     string\n\t\texpected  string\n\t\twantPanic bool\n\t}{\n\t\t{\n\t\t\tname:     \"normal truncation\",\n\t\t\tlength:   5,\n\t\t\tinput:    \"hello world\",\n\t\t\texpected: \"hell…\",\n\t\t},\n\t\t{\n\t\t\tname:     \"no truncation needed\",\n\t\t\tlength:   20,\n\t\t\tinput:    \"short\",\n\t\t\texpected: \"short\",\n\t\t},\n\t\t{\n\t\t\tname:     \"negative length\",\n\t\t\tlength:   -3,\n\t\t\tinput:    \"hello world\",\n\t\t\texpected: \"…ld\",\n\t\t},\n\t\t{\n\t\t\tname:     \"zero length\",\n\t\t\tlength:   0,\n\t\t\tinput:    \"hello\",\n\t\t\texpected: \"…\",\n\t\t},\n\t\t{\n\t\t\tname:     \"unicode characters\",\n\t\t\tlength:   4,\n\t\t\tinput:    \"你好世界\",\n\t\t\texpected: \"你好世…\",\n\t\t},\n\t\t{\n\t\t\tname:     \"empty string\",\n\t\t\tlength:   5,\n\t\t\tinput:    \"\",\n\t\t\texpected: \"\",\n\t\t},\n\t\t{\n\t\t\tname:      \"invalid length type\",\n\t\t\tlength:    \"invalid\",\n\t\t\tinput:     \"hello\",\n\t\t\twantPanic: true,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tif tc.wantPanic {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif r := recover(); r == nil {\n\t\t\t\t\t\tt.Error(\"expected panic but got none\")\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\n\t\t\tresult := TruncE(tc.length, tc.input)\n\t\t\tif result != tc.expected {\n\t\t\t\tt.Errorf(\"expected %q but got %q\", tc.expected, result)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/template/text.go",
    "content": "package template\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"unicode\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n)\n\ntype Text struct {\n\tcontext  Data\n\ttemplate string\n}\n\n// New returns a Text instance from the pool with the given template and context\nfunc get(template string, context any) *Text {\n\tif textPool == nil {\n\t\t// Fallback if pool is not initialized yet\n\t\treturn &Text{context: context, template: template}\n\t}\n\n\ttext := textPool.Get()\n\ttext.template = template\n\ttext.context = context\n\n\treturn text\n}\n\nfunc Render(template string, context any) (string, error) {\n\tt := get(template, context)\n\tdefer t.release()\n\n\tif !strings.Contains(t.template, \"{{\") || !strings.Contains(t.template, \"}}\") {\n\t\treturn t.template, nil\n\t}\n\n\tt.patchTemplate()\n\n\trenderer := renderPool.Get()\n\tdefer renderer.release()\n\n\treturn renderer.execute(t)\n}\n\n// Release resets the Text instance and returns it to the pool\nfunc (t *Text) release() {\n\tt.context = nil\n\tt.template = \"\"\n\n\tif textPool != nil {\n\t\ttextPool.Put(t)\n\t}\n}\n\nfunc (t *Text) patchTemplate() {\n\tfields := &fields{}\n\tfields.init(t.context)\n\n\tvar result, property string\n\tvar inProperty, inTemplate bool\n\tfor i, char := range t.template {\n\t\t// define start or end of template\n\t\tif !inTemplate && char == '{' {\n\t\t\tif i-1 >= 0 && rune(t.template[i-1]) == '{' {\n\t\t\t\tinTemplate = true\n\t\t\t}\n\t\t} else if inTemplate && char == '}' {\n\t\t\tif i-1 >= 0 && rune(t.template[i-1]) == '}' {\n\t\t\t\tinTemplate = false\n\t\t\t}\n\t\t}\n\n\t\tif !inTemplate {\n\t\t\tresult += string(char)\n\t\t\tcontinue\n\t\t}\n\n\t\tswitch char {\n\t\tcase '.':\n\t\t\tvar lastChar rune\n\t\t\tif len(result) > 0 {\n\t\t\t\tlastChar = rune(result[len(result)-1])\n\t\t\t}\n\t\t\t// only replace if we're in a valid property start\n\t\t\t// with a space, { or ( character\n\t\t\tswitch lastChar {\n\t\t\tcase ' ', '{', '(':\n\t\t\t\tproperty += string(char)\n\t\t\t\tinProperty = true\n\t\t\tdefault:\n\t\t\t\tresult += string(char)\n\t\t\t}\n\t\tcase ' ', '}', ')': // space or }\n\t\t\tif !inProperty {\n\t\t\t\tresult += string(char)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tswitch {\n\t\t\tcase strings.HasPrefix(property, \".Segments\") && !strings.HasSuffix(property, \".Contains\"):\n\t\t\t\t// as we can't provide a clean way to access the list\n\t\t\t\t// of segments, we need to replace the property with\n\t\t\t\t// the list of segments so they can be accessed directly\n\t\t\t\tparts := strings.Split(property, \".\")\n\t\t\t\tif len(parts) > 3 {\n\t\t\t\t\tproperty = fmt.Sprintf(`(.Segments.MustGet \"%s\").%s`, parts[2], strings.Join(parts[3:], \".\"))\n\t\t\t\t} else {\n\t\t\t\t\tproperty = fmt.Sprintf(`(.Segments.MustGet \"%s\")`, parts[2])\n\t\t\t\t}\n\t\t\t\tresult += property\n\t\t\t\t// property = strings.Replace(property, \".Segments\", \".Segments.ToSimple\", 1)\n\t\t\t\t// result += property\n\t\t\tcase strings.HasPrefix(property, \".Env.\"):\n\t\t\t\t// we need to replace the property with the getEnv function\n\t\t\t\t// so we can access the environment variables directly\n\t\t\t\tproperty = strings.TrimPrefix(property, \".Env.\")\n\t\t\t\tresult += fmt.Sprintf(`(call .Getenv \"%s\")`, property)\n\t\t\tdefault:\n\t\t\t\t// check if we have the same property in Data\n\t\t\t\t// and replace it with the Data property so it\n\t\t\t\t// can take precedence\n\t\t\t\tif fields.hasField(property) {\n\t\t\t\t\tproperty = \".Data\" + property\n\t\t\t\t}\n\n\t\t\t\t// remove the global reference so we can use it directly\n\t\t\t\tproperty = strings.TrimPrefix(property, globalRef)\n\t\t\t\tresult += property\n\t\t\t}\n\n\t\t\tproperty = \"\"\n\t\t\tresult += string(char)\n\t\t\tinProperty = false\n\t\tdefault:\n\t\t\tif inProperty {\n\t\t\t\tproperty += string(char)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tresult += string(char)\n\t\t}\n\t}\n\n\t// return the result and remaining unresolved property\n\tt.template = result + property\n\n\tlog.Debug(t.template)\n}\n\ntype fields struct {\n\tvalues map[string]bool\n\tsync.RWMutex\n}\n\nfunc (f *fields) init(data any) {\n\tif data == nil {\n\t\treturn\n\t}\n\n\tif f.values == nil {\n\t\tf.values = make(map[string]bool)\n\t}\n\n\tval := reflect.TypeOf(data)\n\tswitch val.Kind() { //nolint:exhaustive\n\tcase reflect.Struct:\n\t\tname := val.Name()\n\n\t\t// check if we already know the fields of this struct\n\t\tif kf, OK := knownFields.Load(name); OK {\n\t\t\tf.append(kf)\n\t\t\treturn\n\t\t}\n\n\t\t// Get struct fields and check embedded types\n\t\tfieldsNum := val.NumField()\n\t\tfor i := range fieldsNum {\n\t\t\tfield := val.Field(i)\n\t\t\tf.add(field.Name)\n\n\t\t\t// If this is an embedded field, get its methods too\n\t\t\tif !field.Anonymous {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tembeddedType := field.Type\n\n\t\t\t// Recursively check if the embedded type is also a struct\n\t\t\tif embeddedType.Kind() == reflect.Struct {\n\t\t\t\tf.init(reflect.New(embeddedType).Elem().Interface())\n\t\t\t}\n\t\t}\n\n\t\t// Get pointer methods\n\t\tptrType := reflect.PointerTo(val)\n\t\tmethodsNum := ptrType.NumMethod()\n\t\tfor i := range methodsNum {\n\t\t\tf.add(ptrType.Method(i).Name)\n\t\t}\n\n\t\tknownFields.Store(name, f)\n\tcase reflect.Map:\n\t\tm, ok := data.(map[string]any)\n\t\tif !ok {\n\t\t\treturn\n\t\t}\n\t\tfor key := range m {\n\t\t\tf.add(key)\n\t\t}\n\tcase reflect.Ptr:\n\t\tf.init(reflect.ValueOf(data).Elem().Interface())\n\t}\n}\n\nfunc (f *fields) append(values any) {\n\tif values == nil {\n\t\treturn\n\t}\n\n\tfields, ok := values.(*fields)\n\tif !ok {\n\t\treturn\n\t}\n\n\tf.Lock()\n\tfields.RLock()\n\n\tdefer func() {\n\t\tf.Unlock()\n\t\tfields.RUnlock()\n\t}()\n\n\tfor key := range fields.values {\n\t\tf.values[key] = true\n\t}\n}\n\nfunc (f *fields) add(field string) {\n\tif field == \"\" {\n\t\treturn\n\t}\n\n\tr := []rune(field)[0]\n\tif !unicode.IsUpper(r) {\n\t\treturn\n\t}\n\n\tf.Lock()\n\tdefer f.Unlock()\n\n\tf.values[field] = true\n}\n\nfunc (f *fields) hasField(field string) bool {\n\tfield = strings.TrimPrefix(field, \".\")\n\n\t// get the first part of the field\n\tfield, _, _ = strings.Cut(field, \".\")\n\n\tf.RLock()\n\tdefer f.RUnlock()\n\n\t_, ok := f.values[field]\n\treturn ok\n}\n"
  },
  {
    "path": "src/template/text_test.go",
    "content": "package template\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/cache\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/maps\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestRenderTemplate(t *testing.T) {\n\ttype Me struct {\n\t\tName string\n\t}\n\n\tcases := []struct {\n\t\tContext     any\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{\n\t\t\tCase:     \"dot literal\",\n\t\t\tExpected: \"Hello .NET \\uE77F\",\n\t\t\tTemplate: \"{{ .Text }} .NET \\uE77F\",\n\t\t\tContext:  struct{ Text string }{Text: \"Hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color override with dots\",\n\t\t\tExpected: \"😺💬<#FF8000> Meow! What should I do next? ...</>\",\n\t\t\tTemplate: \"😺💬<#FF8000> Meow! What should I do next? ...</>\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"tillig's regex\",\n\t\t\tExpected: \" ⎈ hello :: world \",\n\t\t\tTemplate: \" ⎈ {{ replaceP \\\"([a-f0-9]{2})[a-f0-9]{6}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{10}([a-f0-9]{2})\\\" .Context \\\"$1..$2\\\" }}{{ if .Namespace }} :: {{ .Namespace }}{{ end }} \", //nolint:lll\n\t\t\tContext: struct {\n\t\t\t\tContext   string\n\t\t\t\tNamespace string\n\t\t\t}{\n\t\t\t\tContext:   \"hello\",\n\t\t\t\tNamespace: \"world\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Env like property name\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{.EnvLike}} {{.Text2}}\",\n\t\t\tContext: struct {\n\t\t\t\tEnvLike string\n\t\t\t\tText2   string\n\t\t\t}{\n\t\t\t\tEnvLike: \"hello\",\n\t\t\t\tText2:   \"world\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"single property with a dot literal\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{ if eq .Text \\\".Net\\\" }}hello world{{ end }}\",\n\t\t\tContext:  struct{ Text string }{Text: \".Net\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"single property\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{.Text}} world\",\n\t\t\tContext:  struct{ Text string }{Text: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"duplicate property\",\n\t\t\tExpected: \"hello jan posh\",\n\t\t\tTemplate: \"hello {{ .Me.Name }} {{ .Name }}\",\n\t\t\tContext: struct {\n\t\t\t\tName string\n\t\t\t\tMe   Me\n\t\t\t}{\n\t\t\t\tName: \"posh\",\n\t\t\t\tMe: Me{\n\t\t\t\t\tName: \"jan\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:        \"invalid property\",\n\t\t\tShouldError: true,\n\t\t\tTemplate:    \"{{.Durp}} world\",\n\t\t\tContext:     struct{ Text string }{Text: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:        \"invalid template\",\n\t\t\tShouldError: true,\n\t\t\tTemplate:    \"{{ if .Text }} world\",\n\t\t\tContext:     struct{ Text string }{Text: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"if statement true\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{ if .Text }}{{.Text}} world{{end}}\",\n\t\t\tContext:  struct{ Text string }{Text: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"if statement false\",\n\t\t\tExpected: \"world\",\n\t\t\tTemplate: \"{{ if .Text }}{{.Text}} {{end}}world\",\n\t\t\tContext:  struct{ Text string }{Text: \"\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"if statement true with 2 properties\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{.Text}}{{ if .Text2 }} {{.Text2}}{{end}}\",\n\t\t\tContext: struct {\n\t\t\t\tText  string\n\t\t\t\tText2 string\n\t\t\t}{\n\t\t\t\tText:  \"hello\",\n\t\t\t\tText2: \"world\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"if statement false with 2 properties\",\n\t\t\tExpected: \"hello\",\n\t\t\tTemplate: \"{{.Text}}{{ if .Text2 }} {{.Text2}}{{end}}\",\n\t\t\tContext: struct {\n\t\t\t\tText  string\n\t\t\t\tText2 string\n\t\t\t}{\n\t\t\t\tText: \"hello\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"double property template\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{.Text}} {{.Text2}}\",\n\t\t\tContext: struct {\n\t\t\t\tText  string\n\t\t\t\tText2 string\n\t\t\t}{\n\t\t\t\tText:  \"hello\",\n\t\t\t\tText2: \"world\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tCase:     \"sprig - contains\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{ if contains \\\"hell\\\" .Text }}{{.Text}} {{end}}{{.Text2}}\",\n\t\t\tContext: struct {\n\t\t\t\tText  string\n\t\t\t\tText2 string\n\t\t\t}{\n\t\t\t\tText:  \"hello\",\n\t\t\t\tText2: \"world\",\n\t\t\t},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tenv := new(mock.Environment)\n\t\tenv.On(\"Shell\").Return(\"foo\")\n\t\tCache = new(cache.Template)\n\t\tInit(env, nil, nil)\n\n\t\ttext, err := Render(tc.Template, tc.Context)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.NoError(t, err)\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n\nfunc TestRenderTemplateEnvVar(t *testing.T) {\n\tcases := []struct {\n\t\tContext     any\n\t\tEnv         map[string]string\n\t\tCase        string\n\t\tExpected    string\n\t\tTemplate    string\n\t\tShouldError bool\n\t}{\n\t\t{\n\t\t\tCase:        \"nil struct with env var\",\n\t\t\tShouldError: true,\n\t\t\tTemplate:    \"{{.Env.HELLO }} world{{ .Text}}\",\n\t\t\tContext:     nil,\n\t\t\tEnv:         map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"map with env var\",\n\t\t\tExpected: \"hello world\",\n\t\t\tTemplate: \"{{.Env.HELLO}} {{.World}}\",\n\t\t\tContext:  map[string]any{\"World\": \"world\"},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"struct with env var\",\n\t\t\tExpected: \"hello world posh\",\n\t\t\tTemplate: \"{{.Env.HELLO}} world {{ .Text }}\",\n\t\t\tContext:  struct{ Text string }{Text: \"posh\"},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{Case: \"no env var\", Expected: \"hello world\", Template: \"{{.Text}} world\", Context: struct{ Text string }{Text: \"hello\"}},\n\t\t{Case: \"map\", Expected: \"hello world\", Template: \"{{.Text}} world\", Context: map[string]any{\"Text\": \"hello\"}},\n\t\t{Case: \"empty map\", Expected: \" world\", Template: \"{{.Text}} world\", Context: map[string]string{}, ShouldError: true},\n\t\t{\n\t\t\tCase:     \"Struct with duplicate property\",\n\t\t\tExpected: \"posh\",\n\t\t\tTemplate: \"{{ .OS }}\",\n\t\t\tContext:  struct{ OS string }{OS: \"posh\"},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Struct with duplicate property, but global override\",\n\t\t\tExpected: \"darwin\",\n\t\t\tTemplate: \"{{ .$.OS }}\",\n\t\t\tContext:  struct{ OS string }{OS: \"posh\"},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Map with duplicate property\",\n\t\t\tExpected: \"posh\",\n\t\t\tTemplate: \"{{ .OS }}\",\n\t\t\tContext:  map[string]any{\"OS\": \"posh\"},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Non-supported map\",\n\t\t\tExpected: \"darwin\",\n\t\t\tTemplate: \"{{ .OS }}\",\n\t\t\tContext:  map[int]any{},\n\t\t\tEnv:      map[string]string{\"HELLO\": \"hello\"},\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tenv := &mock.Environment{}\n\t\tenv.On(\"Shell\").Return(\"foo\")\n\n\t\tfor k, v := range tc.Env {\n\t\t\tenv.On(\"Getenv\", k).Return(v)\n\t\t}\n\n\t\tCache = &cache.Template{\n\t\t\tSimpleTemplate: cache.SimpleTemplate{\n\t\t\t\tOS: \"darwin\",\n\t\t\t},\n\t\t}\n\t\tInit(env, nil, nil)\n\n\t\ttext, err := Render(tc.Template, tc.Context)\n\t\tif tc.ShouldError {\n\t\t\tassert.Error(t, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n\nfunc TestPatchTemplate(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{\n\t\t\tCase:     \"Literal dots\",\n\t\t\tExpected: \" ... \",\n\t\t\tTemplate: \" ... \",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Literal dot\",\n\t\t\tExpected: \"hello . what's up\",\n\t\t\tTemplate: \"hello . what's up\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Variable\",\n\t\t\tExpected: \"{{range $cpu := .Data.CPU}}{{round $cpu.Mhz 2 }} {{end}}\",\n\t\t\tTemplate: \"{{range $cpu := .CPU}}{{round $cpu.Mhz 2 }} {{end}}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Same prefix\",\n\t\t\tExpected: \"{{ (call .Getenv \\\"HELLO\\\") }} {{ .Data.World }} {{ .Data.WorldTrend }}\",\n\t\t\tTemplate: \"{{ .Env.HELLO }} {{ .World }} {{ .WorldTrend }}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Double use of property with different child\",\n\t\t\tExpected: \"{{ (call .Getenv \\\"HELLO\\\") }} {{ .Data.World.Trend }} {{ .Data.World.Hello }} {{ .Data.World }}\",\n\t\t\tTemplate: \"{{ .Env.HELLO }} {{ .World.Trend }} {{ .World.Hello }} {{ .World }}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Hello world\",\n\t\t\tExpected: \"{{(call .Getenv \\\"HELLO\\\")}} {{.Data.World}}\",\n\t\t\tTemplate: \"{{.Env.HELLO}} {{.World}}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Multiple vars\",\n\t\t\tExpected: \"{{(call .Getenv \\\"HELLO\\\")}} {{.Data.World}} {{.Data.World}}\",\n\t\t\tTemplate: \"{{.Env.HELLO}} {{.World}} {{.World}}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Multiple vars with spaces\",\n\t\t\tExpected: \"{{ (call .Getenv \\\"HELLO\\\") }} {{ .Data.World }} {{ .Data.World }}\",\n\t\t\tTemplate: \"{{ .Env.HELLO }} {{ .World }} {{ .World }}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Braces\",\n\t\t\tExpected: \"{{ if or (.Data.Working.Changed) (.Data.Staging.Changed) }}#FF9248{{ end }}\",\n\t\t\tTemplate: \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Global property override\",\n\t\t\tExpected: \"{{.OS}}\",\n\t\t\tTemplate: \"{{.$.OS}}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Local property override\",\n\t\t\tExpected: \"{{.Data.OS}}\",\n\t\t\tTemplate: \"{{.OS}}\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Keep .Contains intact for Segments\",\n\t\t\tExpected: `{{.Segments.Contains \"Git\"}}`,\n\t\t\tTemplate: `{{.Segments.Contains \"Git\"}}`,\n\t\t},\n\t\t{\n\t\t\tCase:     \"Replace a direct call to .Segments with .Segments.List\",\n\t\t\tExpected: `{{(.Segments.MustGet \"Git\").Repo}}`,\n\t\t\tTemplate: `{{.Segments.Git.Repo}}`,\n\t\t},\n\t}\n\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(\"foo\")\n\tCache = new(cache.Template)\n\tInit(env, nil, nil)\n\n\tfor _, tc := range cases {\n\t\tcontext := map[string]any{\n\t\t\t\"OS\":         true,\n\t\t\t\"World\":      true,\n\t\t\t\"WorldTrend\": \"chaos\",\n\t\t\t\"Working\":    true,\n\t\t\t\"Staging\":    true,\n\t\t\t\"CPU\":        true,\n\t\t}\n\n\t\ttmpl := Text{\n\t\t\ttemplate: tc.Template,\n\t\t\tcontext:  context,\n\t\t}\n\n\t\ttmpl.patchTemplate()\n\t\tassert.Equal(t, tc.Expected, tmpl.template, tc.Case)\n\t}\n}\n\ntype Foo struct{}\n\nfunc (f *Foo) Hello() string {\n\treturn \"hello\"\n}\n\nfunc TestPatchTemplateStruct(t *testing.T) {\n\tenv := new(mock.Environment)\n\tenv.On(\"Shell\").Return(\"foo\")\n\tCache = new(cache.Template)\n\tInit(env, nil, nil)\n\n\ttmpl := Text{\n\t\ttemplate: \"{{ .Hello }}\",\n\t\tcontext:  Foo{},\n\t}\n\n\ttmpl.patchTemplate()\n\tassert.Equal(t, \"{{ .Data.Hello }}\", tmpl.template)\n}\n\nfunc TestSegmentContains(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tTemplate string\n\t}{\n\t\t{Case: \"match\", Expected: \"hello\", Template: `{{ if .Segments.Contains \"Git\" }}hello{{ end }}`},\n\t\t{Case: \"match\", Expected: \"world\", Template: `{{ if .Segments.Contains \"Path\" }}hello{{ else }}world{{ end }}`},\n\t}\n\n\tenv := &mock.Environment{}\n\tsegments := maps.NewConcurrent[any]()\n\tsegments.Set(\"Git\", \"foo\")\n\tenv.On(\"Shell\").Return(\"foo\")\n\n\tCache = &cache.Template{\n\t\tSegments: segments,\n\t}\n\tInit(env, nil, nil)\n\n\tfor _, tc := range cases {\n\t\ttext, _ := Render(tc.Template, nil)\n\t\tassert.Equal(t, tc.Expected, text, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/terminal/iterm.go",
    "content": "package terminal\n\nimport (\n\t\"encoding/gob\"\n\t\"fmt\"\n\t\"slices\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n)\n\nfunc init() {\n\tgob.Register(&ITermFeatures{})\n}\n\ntype iTermFeature string\n\nconst (\n\tPromptMark iTermFeature = \"prompt_mark\"\n\tCurrentDir iTermFeature = \"current_dir\"\n\tRemoteHost iTermFeature = \"remote_host\"\n)\n\ntype ITermFeatures []iTermFeature\n\nfunc (f ITermFeatures) Contains(feature iTermFeature) bool {\n\treturn slices.Contains(f, feature)\n}\n\nfunc RenderItermFeatures(features ITermFeatures, sh, pwd, user, host string) string {\n\tsupportedShells := []string{shell.BASH, shell.ZSH}\n\n\tresult := text.NewBuilder()\n\n\tfor _, feature := range features {\n\t\tswitch feature {\n\t\tcase PromptMark:\n\t\t\tif !slices.Contains(supportedShells, sh) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tresult.WriteString(formats.ITermPromptMark)\n\t\tcase CurrentDir:\n\t\t\tresult.WriteString(fmt.Sprintf(formats.ITermCurrentDir, pwd))\n\t\tcase RemoteHost:\n\t\t\tresult.WriteString(fmt.Sprintf(formats.ITermRemoteHost, user, host))\n\t\t}\n\t}\n\n\treturn result.String()\n}\n"
  },
  {
    "path": "src/terminal/writer.go",
    "content": "package terminal\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/log\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/regex\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/text\"\n\t\"github.com/mattn/go-runewidth\"\n)\n\nfunc init() {\n\trunewidth.DefaultCondition.EastAsianWidth = false\n}\n\ntype style struct {\n\tAnchorStart string\n\tAnchorEnd   string\n\tStart       string\n\tEnd         string\n}\n\nvar (\n\tknownStyles = []*style{\n\t\t{AnchorStart: `<b>`, AnchorEnd: `</b>`, Start: \"\\x1b[1m\", End: \"\\x1b[22m\"},\n\t\t{AnchorStart: `<u>`, AnchorEnd: `</u>`, Start: \"\\x1b[4m\", End: \"\\x1b[24m\"},\n\t\t{AnchorStart: `<o>`, AnchorEnd: `</o>`, Start: \"\\x1b[53m\", End: \"\\x1b[55m\"},\n\t\t{AnchorStart: `<i>`, AnchorEnd: `</i>`, Start: \"\\x1b[3m\", End: \"\\x1b[23m\"},\n\t\t{AnchorStart: `<s>`, AnchorEnd: `</s>`, Start: \"\\x1b[9m\", End: \"\\x1b[29m\"},\n\t\t{AnchorStart: `<d>`, AnchorEnd: `</d>`, Start: \"\\x1b[2m\", End: \"\\x1b[22m\"},\n\t\t{AnchorStart: `<f>`, AnchorEnd: `</f>`, Start: \"\\x1b[5m\", End: \"\\x1b[25m\"},\n\t\t{AnchorStart: `<r>`, AnchorEnd: `</r>`, Start: \"\\x1b[7m\", End: \"\\x1b[27m\"},\n\t}\n\n\tresetStyle      = &style{AnchorStart: \"RESET\", AnchorEnd: `</>`, End: \"\\x1b[0m\"}\n\tbackgroundStyle = &style{AnchorStart: \"BACKGROUND\", AnchorEnd: `</>`, End: \"\\x1b[49m\"}\n\n\tBackgroundColor color.Ansi\n\tCurrentColors   *color.Set\n\tParentColors    []*color.Set\n\tColors          color.String\n\n\tPlain       bool\n\tInteractive bool\n\n\tbuilder strings.Builder\n\tlength  int\n\n\tforegroundColor color.Ansi\n\tbackgroundColor color.Ansi\n\tcurrentColor    color.History\n\trunes           []rune\n\n\tisTransparent bool\n\tisInvisible   bool\n\tisHyperlink   bool\n\n\tShell   string\n\tProgram string\n\n\tformats *shell.Formats\n)\n\nconst (\n\tAnchorRegex      = `^(?P<ANCHOR><(?P<FG>[^,<>]+)?,?(?P<BG>[^<>]+)?>)`\n\tcolorise         = \"\\x1b[%sm\"\n\ttransparentStart = \"\\x1b[0m\\x1b[%s;49m\\x1b[7m\"\n\ttransparentEnd   = \"\\x1b[27m\"\n\tbackgroundEnd    = \"\\x1b[49m\"\n\n\tAnsiRegex = \"[\\u001B\\u009B][[\\\\]()#;?]*(?:(?:(?:[a-zA-Z\\\\d]*(?:;[a-zA-Z\\\\d]*)*)?\\u0007)|(?:(?:\\\\d{1,4}(?:;\\\\d{0,4})*)?[\\\\dA-PRZcf-ntqry=><~]))\"\n\n\tOSC99 = \"osc99\"\n\tOSC7  = \"osc7\"\n\tOSC51 = \"osc51\"\n\n\tANCHOR = \"ANCHOR\"\n\tBG     = \"BG\"\n\tFG     = \"FG\"\n\n\thyperLinkStart   = \"<LINK>\"\n\thyperLinkEnd     = \"</LINK>\"\n\thyperLinkText    = \"<TEXT>\"\n\thyperLinkTextEnd = \"</TEXT>\"\n\n\tempty = \"<>\"\n\n\tstartProgress = \"\\x1b]9;4;3;0\\x07\"\n\tsetProgress   = \"\\x1b]9;4;4;%d\\x07\"\n\tendProgress   = \"\\x1b]9;4;0;0\\x07\"\n\n\tWindowsTerminal = \"Windows Terminal\"\n\tWarp            = \"WarpTerminal\"\n\tITerm           = \"iTerm.app\"\n\tAppleTerminal   = \"Apple_Terminal\"\n\tUnknown         = \"Unknown\"\n)\n\nfunc Init(sh string) {\n\tShell = sh\n\tProgram = getTerminalName()\n\n\tlog.Debug(\"terminal program:\", Program)\n\tlog.Debug(\"terminal shell:\", Shell)\n\n\tcolor.TrueColor = Program != AppleTerminal\n\n\tformats = shell.GetFormats(Shell)\n}\n\nfunc getTerminalName() string {\n\tProgram = os.Getenv(\"TERM_PROGRAM\")\n\tif len(Program) != 0 {\n\t\treturn Program\n\t}\n\n\twtSession := os.Getenv(\"WT_SESSION\")\n\tif len(wtSession) != 0 {\n\t\treturn WindowsTerminal\n\t}\n\n\treturn Unknown\n}\n\nfunc SetColors(background, foreground color.Ansi) {\n\tCurrentColors = &color.Set{\n\t\tBackground: background,\n\t\tForeground: foreground,\n\t}\n}\n\nfunc SetParentColors(background, foreground color.Ansi) {\n\tif ParentColors == nil {\n\t\tParentColors = make([]*color.Set, 0)\n\t}\n\n\tParentColors = append([]*color.Set{{\n\t\tBackground: background,\n\t\tForeground: foreground,\n\t}}, ParentColors...)\n}\n\nfunc ChangeLine(numberOfLines int) string {\n\tif Plain {\n\t\treturn \"\"\n\t}\n\n\tposition := \"B\"\n\n\tif numberOfLines < 0 {\n\t\tposition = \"F\"\n\t\tnumberOfLines = -numberOfLines\n\t}\n\n\treturn fmt.Sprintf(formats.Linechange, numberOfLines, position)\n}\n\nfunc Pwd(pwdType, userName, hostName, pwd string) string {\n\tif Plain {\n\t\treturn \"\"\n\t}\n\n\tswitch pwdType {\n\tcase OSC7:\n\t\treturn fmt.Sprintf(formats.Osc7, hostName, pwd)\n\tcase OSC51:\n\t\treturn fmt.Sprintf(formats.Osc51, userName, hostName, pwd)\n\tcase OSC99:\n\t\tfallthrough\n\tdefault:\n\t\treturn fmt.Sprintf(formats.Osc99, pwd)\n\t}\n}\n\nfunc ClearAfter() string {\n\tif Plain {\n\t\treturn \"\"\n\t}\n\n\treturn formats.ClearLine + formats.ClearBelow\n}\n\nfunc FormatTitle(title string) string {\n\tswitch Shell {\n\t// These shells don't support setting the console title.\n\tcase shell.ELVISH, shell.XONSH:\n\t\treturn \"\"\n\tcase shell.BASH, shell.ZSH:\n\t\ttitle = trimAnsi(title)\n\n\t\tsb := text.NewBuilder()\n\n\t\t// We have to do this to prevent the shell from misidentifying escape sequences.\n\t\tfor _, char := range title {\n\t\t\tescaped, shouldEscape := formats.EscapeSequences[char]\n\t\t\tif shouldEscape {\n\t\t\t\tsb.WriteString(escaped)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tsb.WriteRune(char)\n\t\t}\n\n\t\treturn fmt.Sprintf(formats.Title, sb.String())\n\tdefault:\n\t\treturn fmt.Sprintf(formats.Title, trimAnsi(title))\n\t}\n}\n\nfunc EscapeText(txt string) string {\n\treturn fmt.Sprintf(formats.Escape, txt)\n}\n\nfunc SaveCursorPosition() string {\n\treturn formats.SaveCursorPosition\n}\n\nfunc RestoreCursorPosition() string {\n\treturn formats.RestoreCursorPosition\n}\n\nfunc PromptStart() string {\n\treturn fmt.Sprintf(formats.Escape, \"\\x1b]133;A\\007\")\n}\n\nfunc CommandStart() string {\n\treturn fmt.Sprintf(formats.Escape, \"\\x1b]133;B\\007\")\n}\n\nfunc CommandFinished(code int, ignore bool) string {\n\tif ignore {\n\t\treturn fmt.Sprintf(formats.Escape, \"\\x1b]133;D\\007\")\n\t}\n\n\tmark := fmt.Sprintf(\"\\x1b]133;D;%d\\007\", code)\n\n\treturn fmt.Sprintf(formats.Escape, mark)\n}\n\nfunc LineBreak() string {\n\tcr := fmt.Sprintf(formats.Left, 1000)\n\tlf := fmt.Sprintf(formats.Linechange, 1, \"B\")\n\treturn cr + lf\n}\n\nfunc StartProgress() string {\n\tif Program != WindowsTerminal {\n\t\treturn \"\"\n\t}\n\n\treturn startProgress\n}\n\nfunc SetProgress(percentage int) string {\n\tif Program != WindowsTerminal {\n\t\treturn \"\"\n\t}\n\n\treturn fmt.Sprintf(setProgress, percentage)\n}\n\nfunc StopProgress() string {\n\tif Program != WindowsTerminal {\n\t\treturn \"\"\n\t}\n\n\treturn endProgress\n}\n\nfunc Write(background, foreground color.Ansi, txt string) {\n\tif txt == \"\" {\n\t\treturn\n\t}\n\n\tbackgroundColor, foregroundColor = asAnsiColors(background, foreground)\n\n\t// default to white foreground\n\tif foregroundColor.IsEmpty() {\n\t\tforegroundColor = Colors.ToAnsi(\"white\", false)\n\t}\n\n\t// validate if we start with a color override\n\tmatch := regex.FindNamedRegexMatch(AnchorRegex, txt)\n\tif len(match) != 0 && match[ANCHOR] != hyperLinkStart {\n\t\tcolorOverride := true\n\t\tfor _, style := range knownStyles {\n\t\t\tif match[ANCHOR] != style.AnchorStart {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\twriteEscapedAnsiString(style.Start)\n\t\t\tcolorOverride = false\n\t\t}\n\n\t\tif colorOverride {\n\t\t\tcurrentColor.Add(asAnsiColors(color.Ansi(match[BG]), color.Ansi(match[FG])))\n\t\t}\n\t}\n\n\twriteSegmentColors()\n\n\t// print the hyperlink part AFTER the coloring\n\tif match[ANCHOR] == hyperLinkStart {\n\t\tisHyperlink = true\n\t\tbuilder.WriteString(formats.HyperlinkStart)\n\t}\n\n\ttxt = txt[len(match[ANCHOR]):]\n\trunes = []rune(txt)\n\thyperlinkTextPosition := 0\n\n\tfor i := 0; i < len(runes); i++ {\n\t\ts := runes[i]\n\t\t// ignore everything which isn't overriding\n\t\tif s != '<' {\n\t\t\twrite(s)\n\t\t\tcontinue\n\t\t}\n\n\t\t// color/end overrides first\n\t\ttxt = string(runes[i:])\n\t\tmatch = regex.FindNamedRegexMatch(AnchorRegex, txt)\n\t\tif len(match) > 0 {\n\t\t\t// check for hyperlinks first\n\t\t\tswitch match[ANCHOR] {\n\t\t\tcase hyperLinkStart:\n\t\t\t\tisHyperlink = true\n\t\t\t\ti += len([]rune(match[ANCHOR])) - 1\n\t\t\t\tbuilder.WriteString(formats.HyperlinkStart)\n\t\t\t\tcontinue\n\t\t\tcase hyperLinkText:\n\t\t\t\tisHyperlink = false\n\t\t\t\ti += len([]rune(match[ANCHOR])) - 1\n\t\t\t\thyperlinkTextPosition = i\n\t\t\t\tbuilder.WriteString(formats.HyperlinkCenter)\n\t\t\t\tcontinue\n\t\t\tcase hyperLinkTextEnd:\n\t\t\t\t// this implies there's no text in the hyperlink\n\t\t\t\tif hyperlinkTextPosition+1 == i {\n\t\t\t\t\tbuilder.WriteString(\"link\")\n\t\t\t\t\tlength += 4\n\t\t\t\t}\n\t\t\t\ti += len([]rune(match[ANCHOR])) - 1\n\t\t\t\tcontinue\n\t\t\tcase hyperLinkEnd:\n\t\t\t\ti += len([]rune(match[ANCHOR])) - 1\n\t\t\t\tbuilder.WriteString(formats.HyperlinkEnd)\n\t\t\t\tcontinue\n\t\t\tcase empty:\n\t\t\t\ti += len([]rune(match[ANCHOR])) - 1\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\ti = writeAnchorOverride(match, background, i)\n\t\t\tcontinue\n\t\t}\n\n\t\twrite(s)\n\t}\n\n\t// reset colors\n\twriteEscapedAnsiString(resetStyle.End)\n\n\t// pop last color from the stack\n\tcurrentColor.Pop()\n}\n\nfunc Len() int {\n\treturn length\n}\n\nfunc String() (string, int) {\n\tdefer func() {\n\t\tlength = 0\n\t\tbuilder.Reset()\n\n\t\tisTransparent = false\n\t\tisInvisible = false\n\t}()\n\n\treturn builder.String(), length\n}\n\nfunc writeEscapedAnsiString(txt string) {\n\tif Plain {\n\t\treturn\n\t}\n\n\tif len(formats.Escape) != 0 {\n\t\ttxt = fmt.Sprintf(formats.Escape, txt)\n\t}\n\n\tbuilder.WriteString(txt)\n}\n\nfunc write(s rune) {\n\tif isInvisible {\n\t\treturn\n\t}\n\n\tif isHyperlink {\n\t\tbuilder.WriteRune(s)\n\t\treturn\n\t}\n\n\t// UNSOLVABLE: When \"Interactive\" is true, the prompt length calculation in Bash/Zsh can be wrong, since the final string expansion is done by shells.\n\tlength += runewidth.RuneWidth(s)\n\t// length += utf8.RuneCountInString(string(s))\n\n\tif !Interactive && !Plain {\n\t\tescaped, shouldEscape := formats.EscapeSequences[s]\n\t\tif shouldEscape {\n\t\t\tbuilder.WriteString(escaped)\n\t\t\treturn\n\t\t}\n\t}\n\n\tbuilder.WriteRune(s)\n}\n\nfunc writeSegmentColors() {\n\t// use correct starting colors\n\tbg := backgroundColor\n\tfg := foregroundColor\n\tif !currentColor.Background().IsEmpty() {\n\t\tbg = currentColor.Background()\n\t}\n\tif !currentColor.Foreground().IsEmpty() {\n\t\tfg = currentColor.Foreground()\n\t}\n\n\t// ignore processing fully transparent colors\n\tisInvisible = fg.IsTransparent() && bg.IsTransparent()\n\tif isInvisible {\n\t\treturn\n\t}\n\n\tswitch {\n\tcase fg.IsTransparent() && len(BackgroundColor) != 0:\n\t\tbackground := Colors.ToAnsi(BackgroundColor, false)\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, background))\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, bg.ToForeground()))\n\tcase fg.IsTransparent() && !bg.IsEmpty():\n\t\tisTransparent = true\n\t\twriteEscapedAnsiString(fmt.Sprintf(transparentStart, bg))\n\tdefault:\n\t\tif !bg.IsEmpty() && !bg.IsTransparent() {\n\t\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, bg))\n\t\t}\n\n\t\tif !fg.IsEmpty() && !fg.IsTransparent() {\n\t\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, fg))\n\t\t}\n\t}\n\n\t// set current colors\n\tcurrentColor.Add(bg, fg)\n}\n\nfunc writeAnchorOverride(match map[string]string, background color.Ansi, i int) int {\n\tposition := i\n\t// check color reset first\n\tif match[ANCHOR] == resetStyle.AnchorEnd {\n\t\treturn endColorOverride(position)\n\t}\n\n\tposition += len([]rune(match[ANCHOR])) - 1\n\n\tfor _, style := range knownStyles {\n\t\tif style.AnchorEnd == match[ANCHOR] {\n\t\t\twriteEscapedAnsiString(style.End)\n\t\t\treturn position\n\t\t}\n\t\tif style.AnchorStart == match[ANCHOR] {\n\t\t\twriteEscapedAnsiString(style.Start)\n\t\t\treturn position\n\t\t}\n\t}\n\n\tbgColor := color.Ansi(match[BG])\n\tfgColor := color.Ansi(match[FG])\n\n\tif fgColor.IsTransparent() && bgColor.IsEmpty() {\n\t\tbgColor = background\n\t}\n\n\tbg, fg := asAnsiColors(bgColor, fgColor)\n\n\t// ignore processing fully transparent colors\n\tisInvisible = fg.IsTransparent() && bg.IsTransparent()\n\tif isInvisible {\n\t\treturn position\n\t}\n\n\t// make sure we have colors\n\tif fg.IsEmpty() {\n\t\tfg = foregroundColor\n\t}\n\tif bg.IsEmpty() {\n\t\tbg = backgroundColor\n\t}\n\n\tcurrentColor.Add(bg, fg)\n\n\tif currentColor.Foreground().IsTransparent() && len(BackgroundColor) != 0 {\n\t\tbackground := Colors.ToAnsi(BackgroundColor, false)\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, background))\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background().ToForeground()))\n\t\treturn position\n\t}\n\n\tif currentColor.Foreground().IsTransparent() && !currentColor.Background().IsTransparent() {\n\t\tisTransparent = true\n\t\twriteEscapedAnsiString(fmt.Sprintf(transparentStart, currentColor.Background()))\n\t\treturn position\n\t}\n\n\tif currentColor.Background() != backgroundColor {\n\t\t// end the colors in case we have a transparent background\n\t\tif currentColor.Background().IsTransparent() {\n\t\t\twriteEscapedAnsiString(backgroundEnd)\n\t\t} else {\n\t\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Background()))\n\t\t}\n\t}\n\n\tif currentColor.Foreground() != foregroundColor {\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, currentColor.Foreground()))\n\t}\n\n\treturn position\n}\n\nfunc endColorOverride(position int) int {\n\t// make sure to reset the colors if needed\n\tposition += len([]rune(resetStyle.AnchorEnd)) - 1\n\n\t// do not restore colors at the end of the string, we print it anyways\n\tif position == len(runes)-1 {\n\t\tcurrentColor.Pop()\n\t\treturn position\n\t}\n\n\t// reset colors to previous when we have more than 1 in stack\n\t// as soon as we have  more than 1, we can pop the last one\n\t// and print the previous override as it wasn't ended yet\n\tif currentColor.Len() > 1 {\n\t\tfg := currentColor.Foreground()\n\t\tbg := currentColor.Background()\n\n\t\tcurrentColor.Pop()\n\n\t\tpreviousBg := currentColor.Background()\n\t\tpreviousFg := currentColor.Foreground()\n\n\t\tif isTransparent {\n\t\t\twriteEscapedAnsiString(transparentEnd)\n\t\t}\n\n\t\tif previousBg != bg {\n\t\t\tbackground := fmt.Sprintf(colorise, previousBg)\n\t\t\tif previousBg.IsClear() {\n\t\t\t\tbackground = backgroundStyle.End\n\t\t\t}\n\n\t\t\twriteEscapedAnsiString(background)\n\t\t}\n\n\t\tif previousFg != fg {\n\t\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, previousFg))\n\t\t}\n\n\t\treturn position\n\t}\n\n\t// pop the last colors from the stack\n\tdefer currentColor.Pop()\n\n\t// do not reset when colors are identical\n\tif currentColor.Background() == backgroundColor && currentColor.Foreground() == foregroundColor {\n\t\treturn position\n\t}\n\n\tif isTransparent {\n\t\twriteEscapedAnsiString(transparentEnd)\n\t}\n\n\tif backgroundColor.IsClear() {\n\t\twriteEscapedAnsiString(backgroundStyle.End)\n\t}\n\n\tif currentColor.Background() != backgroundColor && !backgroundColor.IsClear() {\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, backgroundColor))\n\t}\n\n\tif (currentColor.Foreground() != foregroundColor || isTransparent) && !foregroundColor.IsClear() {\n\t\twriteEscapedAnsiString(fmt.Sprintf(colorise, foregroundColor))\n\t}\n\n\tisTransparent = false\n\treturn position\n}\n\nfunc asAnsiColors(background, foreground color.Ansi) (color.Ansi, color.Ansi) {\n\tif background == \"\" {\n\t\tbackground = color.Background\n\t}\n\n\tif foreground == \"\" {\n\t\tforeground = color.Foreground\n\t}\n\n\tbackground = background.Resolve(CurrentColors, ParentColors)\n\tforeground = foreground.Resolve(CurrentColors, ParentColors)\n\n\tif bg, err := Colors.Resolve(background); err == nil {\n\t\tbackground = bg\n\t}\n\n\tif fg, err := Colors.Resolve(foreground); err == nil {\n\t\tforeground = fg\n\t}\n\n\tinverted := foreground == color.Transparent && len(background) != 0\n\n\tbackground = Colors.ToAnsi(background, !inverted)\n\tforeground = Colors.ToAnsi(foreground, false)\n\n\treturn background, foreground\n}\n\nfunc trimAnsi(txt string) string {\n\tif txt == \"\" || !strings.Contains(txt, \"\\x1b\") {\n\t\treturn txt\n\t}\n\treturn regex.ReplaceAllString(AnsiRegex, txt, \"\")\n}\n"
  },
  {
    "path": "src/terminal/writer_hyperlink_test.go",
    "content": "package terminal\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGenerateHyperlinkNoUrl(t *testing.T) {\n\tcases := []struct {\n\t\tText      string\n\t\tShellName string\n\t\tExpected  string\n\t}{\n\t\t{Text: \"sample text with no url\", ShellName: shell.ZSH, Expected: \"%{\\x1b[47m%}%{\\x1b[30m%}sample text with no url%{\\x1b[0m%}\"},\n\t\t{Text: \"sample text with no url\", ShellName: shell.PWSH, Expected: \"\\x1b[47m\\x1b[30msample text with no url\\x1b[0m\"},\n\t\t{Text: \"sample text with no url\", ShellName: shell.BASH, Expected: \"\\\\[\\x1b[47m\\\\]\\\\[\\x1b[30m\\\\]sample text with no url\\\\[\\x1b[0m\\\\]\"},\n\t\t{Text: \"sample text with no url [test]\", ShellName: shell.BASH, Expected: \"\\\\[\\x1b[47m\\\\]\\\\[\\x1b[30m\\\\]sample text with no url [test]\\\\[\\x1b[0m\\\\]\"},\n\t}\n\tfor _, tc := range cases {\n\t\tInit(tc.ShellName)\n\t\tColors = &color.Defaults{}\n\n\t\tWrite(\"white\", \"black\", tc.Text)\n\n\t\tgot, _ := String()\n\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestGenerateHyperlinkWithUrl(t *testing.T) {\n\tcases := []struct {\n\t\tText      string\n\t\tShellName string\n\t\tExpected  string\n\t}{\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT>google</TEXT></LINK> <LINK>http://maps.google.be<TEXT>maps (2/2)</TEXT></LINK>\",\n\t\t\tShellName: shell.FISH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m\\x1b]8;;http://www.google.be\\x1b\\\\google\\x1b]8;;\\x1b\\\\ \\x1b]8;;http://maps.google.be\\x1b\\\\maps (2/2)\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"in <accent><b>pwsh </b></> \",\n\t\t\tShellName: shell.PWSH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30min \\x1b[49m\\x1b[1mpwsh \\x1b[22m\\x1b[47m \\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT>google</TEXT></LINK>\",\n\t\t\tShellName: shell.ZSH,\n\t\t\tExpected:  \"%{\\x1b[47m%}%{\\x1b[30m%}%{\\x1b]8;;http://www.google.be\\x1b\\\\%}google%{\\x1b]8;;\\x1b\\\\%}%{\\x1b[0m%}\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT>google</TEXT></LINK>\",\n\t\t\tShellName: shell.PWSH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m\\x1b]8;;http://www.google.be\\x1b\\\\google\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT>google</TEXT></LINK>\",\n\t\t\tShellName: shell.BASH,\n\t\t\tExpected:  \"\\\\[\\x1b[47m\\\\]\\\\[\\x1b[30m\\\\]\\\\[\\x1b]8;;http://www.google.be\\x1b\\\\\\\\\\\\]google\\\\[\\x1b]8;;\\x1b\\\\\\\\\\\\]\\\\[\\x1b[0m\\\\]\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT>google</TEXT></LINK> <LINK>http://maps.google.be<TEXT>maps</TEXT></LINK>\",\n\t\t\tShellName: shell.FISH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m\\x1b]8;;http://www.google.be\\x1b\\\\google\\x1b]8;;\\x1b\\\\ \\x1b]8;;http://maps.google.be\\x1b\\\\maps\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"[]<LINK>http://www.google.be<TEXT>google</TEXT></LINK>[]\",\n\t\t\tShellName: shell.FISH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m[]\\x1b]8;;http://www.google.be\\x1b\\\\google\\x1b]8;;\\x1b\\\\[]\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT><blue>google</></TEXT></LINK>\",\n\t\t\tShellName: shell.FISH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m\\x1b]8;;http://www.google.be\\x1b\\\\\\x1b[49m\\x1b[34mgoogle\\x1b[47m\\x1b[30m\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT></TEXT></LINK>\",\n\t\t\tShellName: shell.ZSH,\n\t\t\tExpected:  \"%{\\x1b[47m%}%{\\x1b[30m%}%{\\x1b]8;;http://www.google.be\\x1b\\\\%}link%{\\x1b]8;;\\x1b\\\\%}%{\\x1b[0m%}\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT></TEXT></LINK>\",\n\t\t\tShellName: shell.PWSH,\n\t\t\tExpected:  \"\\x1b[47m\\x1b[30m\\x1b]8;;http://www.google.be\\x1b\\\\link\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{\n\t\t\tText:      \"<LINK>http://www.google.be<TEXT></TEXT></LINK>\",\n\t\t\tShellName: shell.BASH,\n\t\t\tExpected:  \"\\\\[\\x1b[47m\\\\]\\\\[\\x1b[30m\\\\]\\\\[\\x1b]8;;http://www.google.be\\x1b\\\\\\\\\\\\]link\\\\[\\x1b]8;;\\x1b\\\\\\\\\\\\]\\\\[\\x1b[0m\\\\]\",\n\t\t},\n\t}\n\tfor _, tc := range cases {\n\t\tInit(tc.ShellName)\n\t\tColors = &color.Defaults{}\n\n\t\tWrite(\"white\", \"black\", tc.Text)\n\n\t\tgot, _ := String()\n\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n\nfunc TestGenerateFileLink(t *testing.T) {\n\tcases := []struct {\n\t\tText     string\n\t\tExpected string\n\t}{\n\t\t{\n\t\t\tText:     `<LINK>file:C:/Program Files (x86)/Common Files/Microsoft Shared/Posh<TEXT>Posh</TEXT></LINK>`,\n\t\t\tExpected: \"\\x1b[47m\\x1b[30m\\x1b]8;;file:C:/Program Files (x86)/Common Files/Microsoft Shared/Posh\\x1b\\\\Posh\\x1b]8;;\\x1b\\\\\\x1b[0m\",\n\t\t},\n\t\t{Text: `<LINK>file:C:/Windows<TEXT>Windows</TEXT></LINK>`, Expected: \"\\x1b[47m\\x1b[30m\\x1b]8;;file:C:/Windows\\x1b\\\\Windows\\x1b]8;;\\x1b\\\\\\x1b[0m\"},\n\t}\n\tfor _, tc := range cases {\n\t\tInit(shell.PWSH)\n\t\tColors = &color.Defaults{}\n\n\t\tWrite(\"white\", \"black\", tc.Text)\n\n\t\tgot, _ := String()\n\n\t\tassert.Equal(t, tc.Expected, got)\n\t}\n}\n"
  },
  {
    "path": "src/terminal/writer_test.go",
    "content": "package terminal\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/color\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/shell\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestWriteANSIColors(t *testing.T) {\n\tcases := []struct {\n\t\tCase               string\n\t\tExpected           string\n\t\tInput              string\n\t\tColors             *color.Set\n\t\tParent             *color.Set\n\t\tTerminalBackground color.Ansi\n\t}{\n\t\t{\n\t\t\tCase:     \"Inline override identical\",\n\t\t\tInput:    \"\\ue0a0saturnay <red>↑</>1\",\n\t\t\tExpected: \"\\x1b[31m\\ue0a0saturnay ↑1\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"red\", Background: color.Transparent},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold\",\n\t\t\tInput:    \"<b>test</b>\",\n\t\t\tExpected: \"\\x1b[1m\\x1b[30mtest\\x1b[22m\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override\",\n\t\t\tInput:    \"<b><#ffffff>test</></b>\",\n\t\t\tExpected: \"\\x1b[1m\\x1b[30m\\x1b[38;2;255;255;255mtest\\x1b[30m\\x1b[22m\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override, flavor 2\",\n\t\t\tInput:    \"<#ffffff><b>test</b></>\",\n\t\t\tExpected: \"\\x1b[38;2;255;255;255m\\x1b[1mtest\\x1b[22m\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Double override\",\n\t\t\tInput:    \"<#ffffff>jan</>@<#ffffff>Jans-MBP</>\",\n\t\t\tExpected: \"\\x1b[48;2;255;87;51m\\x1b[38;2;255;255;255mjan\\x1b[32m@\\x1b[38;2;255;255;255mJans-MBP\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"green\", Background: \"#FF5733\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No color override\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit foreground\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[33mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: color.ParentForeground, Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit background\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[41m\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No parent\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit override foreground\",\n\t\t\tInput:    \"hello <parentForeground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[33mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit override background\",\n\t\t\tInput:    \"hello <black,parentBackground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[41mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit override background, no foreground specified\",\n\t\t\tInput:    \"hello <,parentBackground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[41mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit no parent foreground\",\n\t\t\tInput:    \"hello <parentForeground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[0m\\x1b[37;49m\\x1b[7mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit no parent background\",\n\t\t\tInput:    \"hello <,parentBackground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[49mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit override both\",\n\t\t\tInput:    \"hello <parentForeground,parentBackground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[41m\\x1b[33mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inherit override both inverted\",\n\t\t\tInput:    \"hello <parentBackground,parentForeground>world</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello \\x1b[43m\\x1b[31mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t\tParent:   &color.Set{Foreground: \"yellow\", Background: \"red\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Inline override\",\n\t\t\tInput:    \"hello, <red>world</>, rabbit\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello, \\x1b[31mworld\\x1b[30m, rabbit\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color.Transparent background\",\n\t\t\tInput:    \"hello world\",\n\t\t\tExpected: \"\\x1b[37mhello world\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"white\", Background: color.Transparent},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color.Transparent foreground override\",\n\t\t\tInput:    \"hello <#ffffff>world</>\",\n\t\t\tExpected: \"\\x1b[32mhello \\x1b[38;2;255;255;255mworld\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"green\", Background: color.Transparent},\n\t\t},\n\t\t{\n\t\t\tCase:     \"No foreground\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[48;2;255;87;51m\\x1b[37mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"\", Background: \"#FF5733\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color.Transparent foreground\",\n\t\t\tInput:    \"test\",\n\t\t\tExpected: \"\\x1b[0m\\x1b[38;2;255;87;51;49m\\x1b[7mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: color.Transparent, Background: \"#FF5733\"},\n\t\t},\n\t\t{\n\t\t\tCase:               \"color.Transparent foreground, terminal background set\",\n\t\t\tInput:              \"test\",\n\t\t\tExpected:           \"\\x1b[38;2;33;47;60m\\x1b[48;2;255;87;51mtest\\x1b[0m\",\n\t\t\tColors:             &color.Set{Foreground: color.Transparent, Background: \"#FF5733\"},\n\t\t\tTerminalBackground: \"#212F3C\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"Foreground for foreground override\",\n\t\t\tInput:    \"<foreground>test</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Background for background override\",\n\t\t\tInput:    \"<,background>test</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Google\",\n\t\t\tInput:    \"<blue,white>G</><red,white>o</><yellow,white>o</><blue,white>g</><green,white>l</><red,white>e</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[34mG\\x1b[40m\\x1b[30m\\x1b[47m\\x1b[31mo\\x1b[40m\\x1b[30m\\x1b[47m\\x1b[33mo\\x1b[40m\\x1b[30m\\x1b[47m\\x1b[34mg\\x1b[40m\\x1b[30m\\x1b[47m\\x1b[32ml\\x1b[40m\\x1b[30m\\x1b[47m\\x1b[31me\\x1b[0m\", //nolint: lll\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"black\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Foreground for background override\",\n\t\t\tInput:    \"<background>test</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[37mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Foreground for background vice versa override\",\n\t\t\tInput:    \"<background,foreground>test</>\",\n\t\t\tExpected: \"\\x1b[40m\\x1b[37mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Background for foreground override\",\n\t\t\tInput:    \"<,foreground>test</>\",\n\t\t\tExpected: \"\\x1b[40m\\x1b[30mtest\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Nested override\",\n\t\t\tInput:    \"hello, <red>world, <white>rabbit</> hello</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhello, \\x1b[31mworld, \\x1b[37mrabbit\\x1b[31m hello\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color.Transparent override\",\n\t\t\tInput:    \"home<transparent> / </>code<transparent> / </>src \",\n\t\t\tExpected: \"\\x1b[47m\\x1b[30mhome\\x1b[0m\\x1b[37;49m\\x1b[7m / \\x1b[27m\\x1b[47m\\x1b[30mcode\\x1b[0m\\x1b[37;49m\\x1b[7m / \\x1b[27m\\x1b[47m\\x1b[30msrc \\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Larger than and less than symbols\",\n\t\t\tInput:    \"<red><</><orange>></><yellow><</>\",\n\t\t\tExpected: \"\\x1b[47m\\x1b[31m<\\x1b[30m>\\x1b[33m<\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: \"white\"},\n\t\t},\n\t\t{\n\t\t\tCase:     \"color.Transparent override with parent\",\n\t\t\tInput:    \"hello <#011627,#82AAFF>new</> world\",\n\t\t\tExpected: \"\\x1b[33mhello \\x1b[48;2;130;170;255m\\x1b[38;2;1;22;39mnew\\x1b[49m\\x1b[33m world\\x1b[0m\",\n\t\t\tColors:   &color.Set{Foreground: \"yellow\", Background: \"transparent\"},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tInit(shell.GENERIC)\n\t\tParentColors = []*color.Set{tc.Parent}\n\t\tCurrentColors = tc.Colors\n\t\tBackgroundColor = tc.TerminalBackground\n\t\tColors = &color.Defaults{}\n\n\t\tWrite(tc.Colors.Background, tc.Colors.Foreground, tc.Input)\n\n\t\tgot, _ := String()\n\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n\nfunc TestWriteLength(t *testing.T) {\n\tcases := []struct {\n\t\tColors   *color.Set\n\t\tCase     string\n\t\tInput    string\n\t\tExpected int\n\t}{\n\t\t{\n\t\t\tCase:     \"Emoji\",\n\t\t\tInput:    \" ⏰  \",\n\t\t\tExpected: 5,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold\",\n\t\t\tInput:    \"<b>test</b>\",\n\t\t\tExpected: 4,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override\",\n\t\t\tInput:    \"<b><#ffffff>test</></b>\",\n\t\t\tExpected: 4,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override and link\",\n\t\t\tInput:    \"<b><#ffffff>test</></b> <LINK>https://example.com<TEXT>url</TEXT></LINK>\",\n\t\t\tExpected: 8,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override and link and leading/trailing spaces\",\n\t\t\tInput:    \" <b><#ffffff>test</></b> <LINK>https://example.com<TEXT>url</TEXT></LINK> \",\n\t\t\tExpected: 10,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t\t{\n\t\t\tCase:     \"Bold with color override and link without text and leading/trailing spaces\",\n\t\t\tInput:    \" <b><#ffffff>test</></b> <LINK>https://example.com<TEXT></TEXT></LINK> \",\n\t\t\tExpected: 11,\n\t\t\tColors:   &color.Set{Foreground: \"black\", Background: color.ParentBackground},\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tInit(shell.GENERIC)\n\t\tParentColors = []*color.Set{}\n\t\tCurrentColors = tc.Colors\n\t\tColors = &color.Defaults{}\n\n\t\tWrite(tc.Colors.Background, tc.Colors.Foreground, tc.Input)\n\n\t\t_, got := String()\n\n\t\tassert.Equal(t, tc.Expected, got, tc.Case)\n\t}\n}\n"
  },
  {
    "path": "src/test/AzureRmContext.json",
    "content": "{\n  \"Name\": \"MVP (c2733c30-f2c9-45bd-9f1f-528d7c6191b8) - be96dc2e-13ce-4ee1-9cad-13b52b893716 - jan@ohmyposh.dev\",\n  \"Account\": {\n    \"Id\": \"jan@ohmyposh.dev\",\n    \"Type\": \"User\",\n    \"Tenants\": [\n      \"be96dc2e-13ce-4ee1-9cad-13b52b893716\"\n    ],\n    \"AccessToken\": null,\n    \"Credential\": null,\n    \"TenantMap\": {},\n    \"CertificateThumbprint\": null,\n    \"ExtendedProperties\": {\n      \"Tenants\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n      \"HomeAccountId\": \"360a9158-bf5d-45a7-8539-88e7f6f1d90b.161de531-8316-49b4-88fb-1a669ecc3b5c\",\n      \"Subscriptions\": \"c2733c30-f2c9-45bd-9f1f-528d7c6191b8\"\n    }\n  },\n  \"Environment\": {\n    \"Name\": \"AzurePoshCloud\",\n    \"Type\": \"Built-in\",\n    \"EnableAdfsAuthentication\": false,\n    \"OnPremise\": false,\n    \"ActiveDirectoryServiceEndpointResourceId\": \"https://management.core.windows.net/\",\n    \"AdTenant\": \"Common\",\n    \"GalleryUrl\": \"https://gallery.azure.com/\",\n    \"ManagementPortalUrl\": \"https://portal.azure.com/\",\n    \"ServiceManagementUrl\": \"https://management.core.windows.net/\",\n    \"PublishSettingsFileUrl\": \"https://go.microsoft.com/fwlink/?LinkID=301775\",\n    \"ResourceManagerUrl\": \"https://management.azure.com/\",\n    \"SqlDatabaseDnsSuffix\": \".database.windows.net\",\n    \"StorageEndpointSuffix\": \"core.windows.net\",\n    \"ActiveDirectoryAuthority\": \"https://login.microsoftonline.com/\",\n    \"GraphUrl\": \"https://graph.windows.net/\",\n    \"GraphEndpointResourceId\": \"https://graph.windows.net/\",\n    \"TrafficManagerDnsSuffix\": \"trafficmanager.net\",\n    \"AzureKeyVaultDnsSuffix\": \"vault.azure.net\",\n    \"DataLakeEndpointResourceId\": \"https://datalake.azure.net/\",\n    \"AzureDataLakeStoreFileSystemEndpointSuffix\": \"azuredatalakestore.net\",\n    \"AzureDataLakeAnalyticsCatalogAndJobEndpointSuffix\": \"azuredatalakeanalytics.net\",\n    \"AzureKeyVaultServiceEndpointResourceId\": \"https://vault.azure.net\",\n    \"ContainerRegistryEndpointSuffix\": \"azurecr.io\",\n    \"AzureOperationalInsightsEndpointResourceId\": \"https://api.loganalytics.io\",\n    \"AzureOperationalInsightsEndpoint\": \"https://api.loganalytics.io/v1\",\n    \"AzureAnalysisServicesEndpointSuffix\": \"asazure.windows.net\",\n    \"AnalysisServicesEndpointResourceId\": \"https://region.asazure.windows.net\",\n    \"AzureAttestationServiceEndpointSuffix\": \"attest.azure.net\",\n    \"AzureAttestationServiceEndpointResourceId\": \"https://attest.azure.net\",\n    \"AzureSynapseAnalyticsEndpointSuffix\": \"dev.azuresynapse.net\",\n    \"AzureSynapseAnalyticsEndpointResourceId\": \"https://dev.azuresynapse.net\",\n    \"VersionProfiles\": [],\n    \"ExtendedProperties\": {\n      \"OperationalInsightsEndpoint\": \"https://api.loganalytics.io/v1\",\n      \"OperationalInsightsEndpointResourceId\": \"https://api.loganalytics.io\",\n      \"AzureAnalysisServicesEndpointSuffix\": \"asazure.windows.net\",\n      \"AnalysisServicesEndpointResourceId\": \"https://region.asazure.windows.net\",\n      \"AzureAttestationServiceEndpointSuffix\": \"attest.azure.net\",\n      \"AzureAttestationServiceEndpointResourceId\": \"https://attest.azure.net\",\n      \"AzureSynapseAnalyticsEndpointSuffix\": \"dev.azuresynapse.net\",\n      \"AzureSynapseAnalyticsEndpointResourceId\": \"https://dev.azuresynapse.net\",\n      \"ManagedHsmServiceEndpointResourceId\": \"https://managedhsm.azure.net\",\n      \"ManagedHsmServiceEndpointSuffix\": \"managedhsm.azure.net\",\n      \"MicrosoftGraphEndpointResourceId\": \"https://graph.microsoft.com/\",\n      \"MicrosoftGraphUrl\": \"https://graph.microsoft.com\",\n      \"AzurePurviewEndpointSuffix\": \"purview.azure.net\",\n      \"AzurePurviewEndpointResourceId\": \"https://purview.azure.net\"\n    },\n    \"BatchEndpointResourceId\": \"https://batch.core.windows.net/\"\n  },\n  \"Subscription\": {\n    \"Id\": \"c2733c30-f2c9-45bd-9f1f-528d7c6191b8\",\n    \"Name\": \"MVP\",\n    \"State\": \"Enabled\",\n    \"SubscriptionId\": \"c2733c30-f2c9-45bd-9f1f-528d7c6191b8\",\n    \"TenantId\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n    \"HomeTenantId\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n    \"ManagedByTenantIds\": [],\n    \"CurrentStorageAccountName\": null,\n    \"SubscriptionPolicies\": {\n      \"LocationPlacementId\": \"Public_2014-09-01\",\n      \"QuotaId\": \"MSDN_2014-09-01\",\n      \"SpendingLimit\": \"On\"\n    },\n    \"ExtendedProperties\": {\n      \"Account\": \"jan.de.dobbeleer@gmail.com\",\n      \"Tenants\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n      \"AuthorizationSource\": \"Legacy\",\n      \"SubscriptionPolices\": \"{\\\"locationPlacementId\\\":\\\"Public_2014-09-01\\\",\\\"quotaId\\\":\\\"MSDN_2014-09-01\\\",\\\"spendingLimit\\\":\\\"On\\\"}\",\n      \"HomeTenant\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n      \"Environment\": \"AzureCloud\"\n    },\n    \"CurrentStorageAccount\": null,\n    \"AuthorizationSource\": \"Legacy\",\n    \"Tags\": null\n  },\n  \"Tenant\": {\n    \"Id\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n    \"TenantId\": \"be96dc2e-13ce-4ee1-9cad-13b52b893716\",\n    \"ExtendedProperties\": {},\n    \"TenantCategory\": null,\n    \"Country\": null,\n    \"CountryCode\": null,\n    \"Name\": null,\n    \"Domains\": [],\n    \"DefaultDomain\": null,\n    \"TenantType\": null,\n    \"TenantBrandingLogoUrl\": null\n  },\n  \"TokenCache\": null,\n  \"VersionProfile\": null,\n  \"ExtendedProperties\": {}\n}\n"
  },
  {
    "path": "src/test/azureProfile.json",
    "content": "{\n  \"installationId\": \"8d2919ac-a393-11eb-9100-acde48001122\",\n  \"subscriptions\": [\n    {\n      \"id\": \"g51ds77-a393-11eb-9100-acde48001122\",\n      \"name\": \"AzureCli\",\n      \"state\": \"Powerfull\",\n      \"user\": { \"name\": \"Melinda\", \"type\": \"user\" },\n      \"isDefault\": true,\n      \"tenantId\": \"6js98d-a393-11eb-9100-acde48001122\",\n      \"environmentName\": \"AzureCliCloud\",\n      \"homeTenantId\": \"8d934305-ac9f-46fe-b0e7-50fd32ad2acf\",\n      \"managedByTenants\": []\n    }\n  ]\n}\n"
  },
  {
    "path": "src/test/empty.nuspec",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd\">\n  <metadata>\n    <id>Az.Compute</id>\n    <authors>Microsoft Corporation</authors>\n    <owners>Microsoft Corporation</owners>\n    <requireLicenseAcceptance>true</requireLicenseAcceptance>\n    <licenseUrl>https://aka.ms/azps-license</licenseUrl>\n    <projectUrl>https://github.com/Azure/azure-powershell</projectUrl>\n    <description>Microsoft Azure PowerShell: $(service-name) cmdlets</description>\n    <releaseNotes></releaseNotes>\n    <copyright>Microsoft Corporation. All rights reserved.</copyright>\n    <tags>Azure ResourceManager ARM PSModule $(service-name)</tags>\n    <dependencies>\n      <dependency id=\"Az.Accounts\" version=\"2.2.3\" />\n    </dependencies>\n  </metadata>\n  <files>\n    <file src=\"Az.Compute.format.ps1xml\" />\n    <file src=\"Az.Compute.psd1\" />\n    <file src=\"Az.Compute.psm1\" />\n    <!-- https://github.com/NuGet/Home/issues/3584 -->\n    <file src=\"bin/Az.Compute.private.dll\" target=\"bin\" />\n    <file src=\"bin\\Az.Compute.private.deps.json\" target=\"bin\" />\n    <file src=\"internal\\**\\*.*\" exclude=\"internal\\README.md\" target=\"internal\" />\n    <file src=\"custom\\**\\*.*\" exclude=\"custom\\README.md;custom\\**\\*.cs\" target=\"custom\" />\n    <file src=\"docs\\**\\*.md\" exclude=\"docs\\README.md\" target=\"docs\" />\n    <file src=\"exports\\**\\ProxyCmdletDefinitions.ps1\" target=\"exports\" />\n    <file src=\"utils\\**\\*.*\" target=\"utils\" />\n  </files>\n</package>\n"
  },
  {
    "path": "src/test/go.work",
    "content": "go 1.21"
  },
  {
    "path": "src/test/invalid.nuspec",
    "content": "{}\n"
  },
  {
    "path": "src/test/jandedobbeleer-palette.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"p:session\",\n          \"foreground\": \"p:white\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"p:path\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"~\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea83  {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"p:git\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}p:git-modified{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:git-diverged{{ end }}\",\n            \"{{ if gt .Ahead 0 }}p:git-ahead{{ end }}\",\n            \"{{ if gt .Behind 0 }}p:git-behind{{ end }}\"\n          ],\n          \"foreground\": \"p:git-foreground\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"p:node\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"p:go\",\n          \"foreground\": \"p:black\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"p:julia\",\n          \"foreground\": \"p:black\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"p:python\",\n          \"foreground\": \"p:black\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"p:ruby\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"p:azfunc\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background_templates\": [\n            \"{{if contains \\\"default\\\" .Profile}}p:aws-default{{end}}\",\n            \"{{if contains \\\"jan\\\" .Profile}}p:aws-jan{{end}}\"\n          ],\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_default\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"p:root\",\n          \"foreground\": \"p:black\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0ad \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"p:executiontime\",\n          \"foreground\": \"p:white\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> \\ueba2{{ .FormattedMs }}\\u2800\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"p:exit\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}p:exit-red{{ end }}\"\n          ],\n          \"foreground\": \"p:white\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\ue23a \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"segments\": [\n        {\n          \"background\": \"p:shell\",\n          \"foreground\": \"p:white\",\n          \"style\": \"plain\",\n          \"template\": \"<#0077c2,transparent>\\ue0b6</> \\uf489 {{ .Name }} <transparent,#0077c2>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"p:ytm\",\n          \"foreground\": \"p:black\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"paused_icon\": \"\\uf04c \",\n            \"playing_icon\": \"\\uf04b \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf167 {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"ytm\"\n        },\n        {\n          \"background\": \"p:battery\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}p:battery-charging{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}p:battery-discharging{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}p:battery-charged{{end}}\"\n          ],\n          \"foreground\": \"p:white\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ue234 \",\n            \"discharging_icon\": \"\\ue231 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"p:time\",\n          \"foreground\": \"p:black\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"palette\": {\n    \"aws-default\": \"#FFA400\",\n    \"aws-jan\": \"#F1184C\",\n    \"azfunc\": \"#FEAC19\",\n    \"battery\": \"#F36943\",\n    \"battery-charged\": \"#4CAF50\",\n    \"battery-charging\": \"#40C4FF\",\n    \"battery-discharging\": \"#FF5722\",\n    \"black\": \"#111111\",\n    \"executiontime\": \"#83769C\",\n    \"exit\": \"#00897B\",\n    \"exit-red\": \"#E91E63\",\n    \"git\": \"#FFFB38\",\n    \"git-ahead\": \"#B388FF\",\n    \"git-behind\": \"#B388FF\",\n    \"git-diverged\": \"#FF4500\",\n    \"git-foreground\": \"#193549\",\n    \"git-modified\": \"#FF9248\",\n    \"go\": \"#8ED1F7\",\n    \"julia\": \"#4063D8\",\n    \"node\": \"#6CA35E\",\n    \"path\": \"#FF479C\",\n    \"python\": \"#FFDE57\",\n    \"root\": \"#FFFF66\",\n    \"ruby\": \"#AE1401\",\n    \"session\": \"#C386F1\",\n    \"shell\": \"#0077C2\",\n    \"time\": \"#2E9599\",\n    \"white\": \"#FFFFFF\",\n    \"ytm\": \"#1BD760\"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "src/test/jandedobbeleer.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#c386f1\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ff479c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"~\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea83  {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#8ED1F7\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#4063D8\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#FFDE57\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#AE1401\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#FEAC19\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background_templates\": [\n            \"{{if contains \\\"default\\\" .Profile}}#FFA400{{end}}\",\n            \"{{if contains \\\"jan\\\" .Profile}}#f1184c{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_default\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0ad \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> \\ueba2{{ .FormattedMs }}\\u2800\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#00897b\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#e91e63{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\ue23a \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"segments\": [\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#0077c2,transparent>\\ue0b6</> \\uf489 {{ .Name }} <transparent,#0077c2>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#1BD760\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"paused_icon\": \"\\uf04c \",\n            \"playing_icon\": \"\\uf04b \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf167 {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"ytm\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ue234 \",\n            \"discharging_icon\": \"\\ue231 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "src/test/kubectl.yml",
    "content": "apiVersion: v1\nclusters: null\ncontexts:\n  - context:\n      cluster: '%s'\n      user: '%s'\n      namespace: '%s'\n    name: jan\ncurrent-context: '%s'\nkind: Config\npreferences: {}\nusers: null\n"
  },
  {
    "path": "src/test/nba/schedule.json",
    "content": "{\n  \"resource\": \"internationalbroadcasterschedule\",\n  \"parameters\": {\n    \"LeagueID\": \"00\",\n    \"Season\": \"2023\",\n    \"RegionID\": 1,\n    \"Date\": \"10/26/2023\",\n    \"EST\": \"Y\"\n  },\n  \"resultSets\": [\n    {\n      \"NextGameList\": [\n        {\n          \"gameID\": \"0022300075\",\n          \"vtCity\": \"Philadelphia\",\n          \"vtNickName\": \"76ers\",\n          \"vtShortName\": \"Philadelphia\",\n          \"vtAbbreviation\": \"PHI\",\n          \"htCity\": \"Milwaukee\",\n          \"htNickName\": \"Bucks\",\n          \"htShortName\": \"Milwaukee\",\n          \"htAbbreviation\": \"MIL\",\n          \"date\": \"10/26/2023\",\n          \"time\": \"07:30 PM\",\n          \"day\": \"Thu\",\n          \"broadcasters\": [\n            {\n              \"broadcastID\": \"10\",\n              \"broadcasterName\": \"TNT\",\n              \"tapeDelayComments\": \"\"\n            }\n          ]\n        },\n        {\n          \"gameID\": \"0022300076\",\n          \"vtCity\": \"Phoenix\",\n          \"vtNickName\": \"Suns\",\n          \"vtShortName\": \"Phoenix\",\n          \"vtAbbreviation\": \"PHX\",\n          \"htCity\": \"Los Angeles\",\n          \"htNickName\": \"Lakers\",\n          \"htShortName\": \"L.A. Lakers\",\n          \"htAbbreviation\": \"LAL\",\n          \"date\": \"10/26/2023\",\n          \"time\": \"10:00 PM\",\n          \"day\": \"Thu\",\n          \"broadcasters\": [\n            {\n              \"broadcastID\": \"10\",\n              \"broadcasterName\": \"TNT\",\n              \"tapeDelayComments\": \"\"\n            }\n          ]\n        }\n      ]\n    },\n    {\n      \"CompleteGameList\": [\n        {\n          \"gameID\": \"0022300075\",\n          \"vtCity\": \"Philadelphia\",\n          \"vtNickName\": \"76ers\",\n          \"vtShortName\": \"Philadelphia\",\n          \"vtAbbreviation\": \"PHI\",\n          \"htCity\": \"Milwaukee\",\n          \"htNickName\": \"Bucks\",\n          \"htShortName\": \"Milwaukee\",\n          \"htAbbreviation\": \"MIL\",\n          \"date\": \"10/26/2023\",\n          \"time\": \"07:30 PM\",\n          \"day\": \"Thu\",\n          \"broadcastID\": \"10\",\n          \"broadcasterName\": \"TNT\",\n          \"tapeDelayComments\": \"\"\n        },\n        {\n          \"gameID\": \"0022300076\",\n          \"vtCity\": \"Phoenix\",\n          \"vtNickName\": \"Suns\",\n          \"vtShortName\": \"Phoenix\",\n          \"vtAbbreviation\": \"PHX\",\n          \"htCity\": \"Los Angeles\",\n          \"htNickName\": \"Lakers\",\n          \"htShortName\": \"L.A. Lakers\",\n          \"htAbbreviation\": \"LAL\",\n          \"date\": \"10/26/2023\",\n          \"time\": \"10:00 PM\",\n          \"day\": \"Thu\",\n          \"broadcastID\": \"10\",\n          \"broadcasterName\": \"TNT\",\n          \"tapeDelayComments\": \"\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "src/test/nba/score.json",
    "content": "{\n  \"meta\": {\n    \"version\": 1,\n    \"request\": \"https://nba-prod-us-east-1-mediaops-stats.s3.amazonaws.com/NBA/liveData/scoreboard/todaysScoreboard_00.json\",\n    \"time\": \"2023-10-19 01:17:57.1757\",\n    \"code\": 200\n  },\n  \"scoreboard\": {\n    \"gameDate\": \"2023-10-19\",\n    \"leagueId\": \"00\",\n    \"leagueName\": \"National Basketball Association\",\n    \"games\": [\n      {\n        \"gameId\": \"0012300060\",\n        \"gameCode\": \"20231019/BOSCHA\",\n        \"gameStatus\": 2,\n        \"gameStatusText\": \"Q1 8:23\",\n        \"period\": 0,\n        \"gameClock\": \"Q1 8:23\",\n        \"gameTimeUTC\": \"2023-10-19T23:00:00Z\",\n        \"gameEt\": \"2023-10-19T19:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612766,\n          \"teamName\": \"Hornets\",\n          \"teamCity\": \"Charlotte\",\n          \"teamTricode\": \"CHA\",\n          \"wins\": 1,\n          \"losses\": 0,\n          \"score\": 13,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612738,\n          \"teamName\": \"Celtics\",\n          \"teamCity\": \"Boston\",\n          \"teamTricode\": \"BOS\",\n          \"wins\": 0,\n          \"losses\": 1,\n          \"score\": 8,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"CHA\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"BOS\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      },\n      {\n        \"gameId\": \"0012300061\",\n        \"gameCode\": \"20231019/MINCHI\",\n        \"gameStatus\": 1,\n        \"gameStatusText\": \"8:00 pm ET\",\n        \"period\": 0,\n        \"gameClock\": \"\",\n        \"gameTimeUTC\": \"2023-10-20T00:00:00Z\",\n        \"gameEt\": \"2023-10-19T20:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612741,\n          \"teamName\": \"Bulls\",\n          \"teamCity\": \"Chicago\",\n          \"teamTricode\": \"CHI\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612750,\n          \"teamName\": \"Timberwolves\",\n          \"teamCity\": \"Minnesota\",\n          \"teamTricode\": \"MIN\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"CHI\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"MIN\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      },\n      {\n        \"gameId\": \"0012300062\",\n        \"gameCode\": \"20231019/DETOKC\",\n        \"gameStatus\": 1,\n        \"gameStatusText\": \"8:00 pm ET\",\n        \"period\": 0,\n        \"gameClock\": \"\",\n        \"gameTimeUTC\": \"2023-10-20T00:00:00Z\",\n        \"gameEt\": \"2023-10-19T20:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612760,\n          \"teamName\": \"Thunder\",\n          \"teamCity\": \"Oklahoma City\",\n          \"teamTricode\": \"OKC\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612765,\n          \"teamName\": \"Pistons\",\n          \"teamCity\": \"Detroit\",\n          \"teamTricode\": \"DET\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"OKC\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"DET\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      },\n      {\n        \"gameId\": \"0012300063\",\n        \"gameCode\": \"20231019/PHXLAL\",\n        \"gameStatus\": 1,\n        \"gameStatusText\": \"10:00 pm ET\",\n        \"period\": 0,\n        \"gameClock\": \"\",\n        \"gameTimeUTC\": \"2023-10-20T02:00:00Z\",\n        \"gameEt\": \"2023-10-19T22:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612747,\n          \"teamName\": \"Lakers\",\n          \"teamCity\": \"Los Angeles\",\n          \"teamTricode\": \"LAL\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612756,\n          \"teamName\": \"Suns\",\n          \"teamCity\": \"Phoenix\",\n          \"teamTricode\": \"PHX\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"LAL\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"PHX\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      },\n      {\n        \"gameId\": \"0012300064\",\n        \"gameCode\": \"20231019/DENLAC\",\n        \"gameStatus\": 1,\n        \"gameStatusText\": \"10:00 pm ET\",\n        \"period\": 0,\n        \"gameClock\": \"\",\n        \"gameTimeUTC\": \"2023-10-20T02:00:00Z\",\n        \"gameEt\": \"2023-10-19T22:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612746,\n          \"teamName\": \"Clippers\",\n          \"teamCity\": \"LA\",\n          \"teamTricode\": \"LAC\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612743,\n          \"teamName\": \"Nuggets\",\n          \"teamCity\": \"Denver\",\n          \"teamTricode\": \"DEN\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"LAC\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"DEN\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      },\n      {\n        \"gameId\": \"0012300065\",\n        \"gameCode\": \"20231019/UTASAC\",\n        \"gameStatus\": 1,\n        \"gameStatusText\": \"10:00 pm ET\",\n        \"period\": 0,\n        \"gameClock\": \"\",\n        \"gameTimeUTC\": \"2023-10-20T02:00:00Z\",\n        \"gameEt\": \"2023-10-19T22:00:00Z\",\n        \"regulationPeriods\": 4,\n        \"ifNecessary\": false,\n        \"seriesGameNumber\": \"\",\n        \"seriesText\": \"Preseason\",\n        \"seriesConference\": \"\",\n        \"poRoundDesc\": \"\",\n        \"gameSubtype\": \"\",\n        \"homeTeam\": {\n          \"teamId\": 1610612758,\n          \"teamName\": \"Kings\",\n          \"teamCity\": \"Sacramento\",\n          \"teamTricode\": \"SAC\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"awayTeam\": {\n          \"teamId\": 1610612762,\n          \"teamName\": \"Jazz\",\n          \"teamCity\": \"Utah\",\n          \"teamTricode\": \"UTA\",\n          \"wins\": 0,\n          \"losses\": 0,\n          \"score\": 0,\n          \"seed\": null,\n          \"inBonus\": null,\n          \"timeoutsRemaining\": 0,\n          \"periods\": [\n            {\n              \"period\": 1,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 2,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 3,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            },\n            {\n              \"period\": 4,\n              \"periodType\": \"REGULAR\",\n              \"score\": 0\n            }\n          ]\n        },\n        \"gameLeaders\": {\n          \"homeLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"SAC\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          },\n          \"awayLeaders\": {\n            \"personId\": 0,\n            \"name\": \"\",\n            \"jerseyNum\": \"\",\n            \"position\": \"\",\n            \"teamTricode\": \"UTA\",\n            \"playerSlug\": null,\n            \"points\": 0,\n            \"rebounds\": 0,\n            \"assists\": 0\n          }\n        },\n        \"pbOdds\": {\n          \"team\": null,\n          \"odds\": 0.0,\n          \"suspended\": 0\n        }\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "src/test/oh-my-posh.psd1",
    "content": "﻿#\r\n# Module manifest for module 'oh-my-posh'\r\n#\r\n# Generated by: Jan\r\n#\r\n# Generated on: 28-Jun-16\r\n#\r\n\r\n@{\r\n\r\n# Version number of this module.\r\nModuleVersion = '1.0.0.0'\r\n\r\n# Script module or binary module file associated with this manifest.\r\nRootModule = 'oh-my-posh.psm1'\r\n\r\n# ID used to uniquely identify this module\r\nGUID = '7d7c4a78-e2fe-4e5f-9510-34ac893e4562'\r\n\r\n# Company or vendor of this module\r\nCompanyName = 'Unknown'\r\n\r\n# Author of this module\r\nAuthor = 'Jan De Dobbeleer'\r\n\r\n# Copyright statement for this module\r\nCopyright = '(c) 2018 Jan De Dobbeleer. All rights reserved.'\r\n\r\n# Description of the functionality provided by this module\r\nDescription = 'Theming capabilities for the PowerShell prompt in ConEmu'\r\n\r\n# Minimum version of the Windows PowerShell engine required by this module\r\nPowerShellVersion = '5.0'\r\n\r\n# List of all files packaged with this module\r\nFileList = @('defaults.ps1', 'Themes/Agnoster.psm1', 'Themes/Avit.psm1', 'Themes/Darkblood.psm1', 'Themes/Fish.psm1', 'Themes/Honukai.psm1', 'Themes/Paradox.psm1', 'Themes/Sorin.psm1', 'Helpers/PoshGit.ps1', 'Helpers/Prompt.ps1')\r\n\r\n# Cmdlets to export from this module\r\nCmdletsToExport = @()\r\n\r\n# Variables to export from this module\r\nVariablesToExport = @()\r\n\r\n# Aliases to export from this module\r\nAliasesToExport = '*'\r\n\r\n# Functions to export from this module\r\nFunctionsToExport = @('Write-ColorPreview',\r\n                      'Show-Colors',\r\n                      'Show-ThemeColors',\r\n                      'Show-ThemeSymbols',\r\n                      'Get-Theme',\r\n                      'Set-Theme',\r\n                      'Get-VCSStatus',\r\n                      'Get-VcsInfo',\r\n                      'Get-FormattedRootLocation',\r\n                      'Get-ShortPath',\r\n                      'Get-FullPath',\r\n                      'Set-CursorForRightBlockWrite',\r\n                      'Set-CursorUp',\r\n                      'Test-VirtualEnv',\r\n                      'Get-VirtualEnvName',\r\n                      'Test-NotDefaultUser',\r\n                      'Test-Administrator',\r\n                      'Get-ComputerName',\r\n                      'Set-Newline',\r\n                      'Get-BatteryInfo',\r\n                      'Get-ThemesLocation'\r\n                      'Set-Prompt')\r\n\r\n# Private data to pass to the module specified in RootModule. This may also contain a PSData hashtable with additional module metadata used by PowerShell.\r\nPrivateData = @{\r\n\r\n    PSData = @{\r\n\r\n        # Tags applied to this module. These help with module discovery in online galleries.\r\n        Tags = @('git', 'agnoster', 'theme', 'zsh', 'posh-git', 'prompt', 'paradox')\r\n\r\n        # A URL to the license for this module.\r\n        LicenseUri = 'https://github.com/JanDeDobbeleer/oh-my-posh2/blob/master/LICENSE'\r\n\r\n        # A URL to the main website for this project.\r\n        ProjectUri = 'https://github.com/JanDeDobbeleer/oh-my-posh2'\r\n\r\n    } # End of PSData hashtable\r\n\r\n} # End of PrivateData hashtable\r\n\r\n}\r\n"
  },
  {
    "path": "src/test/signing/checksums.txt",
    "content": "4ad2e70db23f6c0441df61a07370d352081e93fab32867e797d6dfa3f45814ce  posh-windows-arm64.exe\n"
  },
  {
    "path": "src/test/signing/checksums.txt.invalid.sig",
    "content": "v3.*\nkWbJ.\u001a\u001asGuee5ܨ[lU\u001a{\u000e؅R-ͅX_\u0011\fE\u001d7`\u00045\f}-\u001dW.QS\"} C]'FZ\u0002PhYʩɯ7nD\u00030l8O>}.<,\u001c \u0014\u0013\b+\u001a\u000f%\u0007FP\n^\nK\"Z\u0001=mx8py08[|z&\u0003y\u0014lu\f\u0014Q\u001c$\u001b@Ԃ>\u001a'nW8\u000e\u0010M.\u0019\bt֦"
  },
  {
    "path": "src/test/signing/checksums.txt.sig",
    "content": "3JS\u0005Dʻ9IbfC(6cUF,ogPH\r܋if\u0013F_\u000b"
  },
  {
    "path": "src/test/terraform.tfstate",
    "content": "{\n  \"version\": 4,\n  \"terraform_version\": \"0.12.24\",\n  \"serial\": 22,\n  \"lineage\": \"6cc278b4-0426-a833-9920-356a6635038c\"\n}\n"
  },
  {
    "path": "src/test/umbraco/ANonUmbracoProject.csproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"12.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <Import Project=\"..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.props\" Condition=\"Exists('..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.props')\" />\n  <Import Project=\"..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\\build\\net45\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props\" Condition=\"Exists('..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\\build\\net45\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')\" />\n  <Import Project=\"..\\packages\\uSync.3.2.2.740\\build\\uSync.props\" Condition=\"Exists('..\\packages\\uSync.3.2.2.740\\build\\uSync.props')\" />\n  <Import Project=\"..\\packages\\Microsoft.Net.Compilers.1.0.0\\build\\Microsoft.Net.Compilers.props\" Condition=\"Exists('..\\packages\\Microsoft.Net.Compilers.1.0.0\\build\\Microsoft.Net.Compilers.props')\" />\n  <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n  <PropertyGroup>\n    <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n    <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n    <ProductVersion>\n    </ProductVersion>\n    <SchemaVersion>2.0</SchemaVersion>\n    <ProjectGuid>{EA5AED40-16B4-41F6-98BB-C4EE8F6B1893}</ProjectGuid>\n    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>MyOtherProject.Site</RootNamespace>\n    <AssemblyName>MyOtherProject.Site</AssemblyName>\n    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>\n    <UseIISExpress>true</UseIISExpress>\n    <IISExpressSSLPort>44333</IISExpressSSLPort>\n    <IISExpressAnonymousAuthentication />\n    <IISExpressWindowsAuthentication />\n    <IISExpressUseClassicPipelineMode />\n    <UseGlobalApplicationHostFile />\n    <NuGetPackageImportStamp>\n    </NuGetPackageImportStamp>\n    <Use64BitIISExpress />\n    <FileUpgradeFlags>\n    </FileUpgradeFlags>\n    <UpgradeBackupLocation>\n    </UpgradeBackupLocation>\n    <OldToolsVersion>12.0</OldToolsVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>\n  </PropertyGroup>\n  <ItemGroup>\n    <Reference Include=\"AngularGoogleMaps, Version=2.0.1.35, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\AngularGoogleMaps.2.0.1\\lib\\net45\\AngularGoogleMaps.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Archetype, Version=1.13.1.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Archetype.Binaries.1.13.1\\lib\\net40\\Archetype.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\AutoMapper.3.3.1\\lib\\net40\\AutoMapper.dll</HintPath>\n    </Reference>\n    <Reference Include=\"AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\AutoMapper.3.3.1\\lib\\net40\\AutoMapper.Net4.dll</HintPath>\n    </Reference>\n    <Reference Include=\"businesslogic, Version=1.0.7706.20575, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\businesslogic.dll</HintPath>\n    </Reference>\n    <Reference Include=\"ClientDependency.Core, Version=1.9.9.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ClientDependency.1.9.9\\lib\\net45\\ClientDependency.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"ClientDependency.Core.Mvc, Version=1.9.3.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ClientDependency-Mvc5.1.9.3\\lib\\net45\\ClientDependency.Core.Mvc.dll</HintPath>\n    </Reference>\n    <Reference Include=\"cms, Version=1.0.7706.20575, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\cms.dll</HintPath>\n    </Reference>\n    <Reference Include=\"controls, Version=1.0.7706.20576, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\controls.dll</HintPath>\n    </Reference>\n    <Reference Include=\"CookComputing.XmlRpcV2, Version=2.5.0.0, Culture=neutral, PublicKeyToken=a7d6e17aa302004d, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\xmlrpcnet.2.5.0\\lib\\net20\\CookComputing.XmlRpcV2.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Diplo.TraceLogViewer, Version=2.2.6.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\DiploTraceLogViewer.2.2.6\\lib\\net45\\Diplo.TraceLogViewer.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Examine, Version=0.1.90.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Examine.0.1.90\\lib\\net45\\Examine.dll</HintPath>\n    </Reference>\n    <Reference Include=\"FoolproofValidation, Version=0.9.5851.39121, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Foolproof.0.9.4518\\lib\\net45\\FoolproofValidation.dll</HintPath>\n    </Reference>   \n    <Reference Include=\"HtmlAgilityPack, Version=1.8.8.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\HtmlAgilityPack.1.8.8\\lib\\Net45\\HtmlAgilityPack.dll</HintPath>\n    </Reference>\n    <Reference Include=\"ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\SharpZipLib.0.86.0\\lib\\20\\ICSharpCode.SharpZipLib.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"ImageProcessor, Version=2.7.0.100, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ImageProcessor.2.7.0.100\\lib\\net452\\ImageProcessor.dll</HintPath>\n    </Reference>\n    <Reference Include=\"ImageProcessor.Web, Version=4.10.0.100, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ImageProcessor.Web.4.10.0.100\\lib\\net452\\ImageProcessor.Web.dll</HintPath>\n    </Reference>\n    <Reference Include=\"ImageResizer, Version=3.4.3.103, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ImageResizer.3.4.3\\lib\\ImageResizer.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"ImageResizer.Mvc, Version=3.4.3.103, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ImageResizer.Mvc.3.4.3\\lib\\ImageResizer.Mvc.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"ImageResizer.Plugins.DiskCache, Version=3.4.3.103, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\ImageResizer.Plugins.DiskCache.3.4.3\\lib\\ImageResizer.Plugins.DiskCache.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"interfaces, Version=1.0.7706.20568, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\interfaces.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Jumoo.uSync.BackOffice, Version=3.2.2.740, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\uSync.3.2.2.740\\lib\\net45\\Jumoo.uSync.BackOffice.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Jumoo.uSync.Core, Version=5.5.2.740, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\uSync.Core.5.5.2.740\\lib\\net45\\Jumoo.uSync.Core.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"log4net, Version=2.0.12.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\log4net.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Log4Net.Async, Version=2.0.4.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Log4Net.Async.2.0.4\\lib\\net40\\Log4Net.Async.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Lucene.Net.2.9.4.1\\lib\\net40\\Lucene.Net.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MailChimp.Net, Version=4.2.1.0, Culture=neutral, PublicKeyToken=37d26d538413c581\">\n      <HintPath>..\\packages\\MailChimp.Net.V3.4.2.1\\lib\\net45\\MailChimp.Net.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MailChimp.Net.V3, Version=1.7.0.0, Culture=neutral, PublicKeyToken=37d26d538413c581, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\MailChimp.Net.V3.1.7.0.0\\lib\\net45\\MailChimp.Net.V3.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MarkdownSharp, Version=1.14.5.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Markdown.1.14.7\\lib\\net45\\MarkdownSharp.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.Agent.Intercept, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.Agent.Intercept.2.4.0\\lib\\net45\\Microsoft.AI.Agent.Intercept.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.DependencyCollector, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.DependencyCollector.2.4.1\\lib\\net45\\Microsoft.AI.DependencyCollector.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.PerfCounterCollector, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.PerfCounterCollector.2.4.1\\lib\\net45\\Microsoft.AI.PerfCounterCollector.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.ServerTelemetryChannel, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.2.4.0\\lib\\net45\\Microsoft.AI.ServerTelemetryChannel.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.Web, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.Web.2.4.1\\lib\\net45\\Microsoft.AI.Web.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AI.WindowsServer, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.WindowsServer.2.4.1\\lib\\net45\\Microsoft.AI.WindowsServer.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.ApplicationBlocks.Data, Version=1.0.1559.20655, Culture=neutral\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\Microsoft.ApplicationBlocks.Data.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.ApplicationInsights, Version=2.4.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.2.4.0\\lib\\net45\\Microsoft.ApplicationInsights.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.ApplicationInsights.Log4NetAppender, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.ApplicationInsights.Log4NetAppender.2.4.1\\lib\\net45\\Microsoft.ApplicationInsights.Log4NetAppender.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.Identity.Core.2.2.2\\lib\\net45\\Microsoft.AspNet.Identity.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AspNet.Identity.Owin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.Identity.Owin.2.2.2\\lib\\net45\\Microsoft.AspNet.Identity.Owin.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AspNet.SignalR.Core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.SignalR.Core.2.4.1\\lib\\net45\\Microsoft.AspNet.SignalR.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.AspNet.TelemetryCorrelation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.TelemetryCorrelation.1.0.0\\lib\\net45\\Microsoft.AspNet.TelemetryCorrelation.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.CodeAnalysis, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.CodeAnalysis.Common.1.0.0\\lib\\net45\\Microsoft.CodeAnalysis.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.CodeAnalysis.CSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.CodeAnalysis.CSharp.1.0.0\\lib\\net45\\Microsoft.CodeAnalysis.CSharp.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\\lib\\net45\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.CSharp\" />\n    <Reference Include=\"Microsoft.IO.RecyclableMemoryStream, Version=1.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.IO.RecyclableMemoryStream.1.2.2\\lib\\net45\\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Owin, Version=4.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Owin.4.0.1\\lib\\net45\\Microsoft.Owin.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Owin.Host.SystemWeb, Version=4.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Owin.Host.SystemWeb.4.0.1\\lib\\net45\\Microsoft.Owin.Host.SystemWeb.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Owin.Security, Version=4.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Owin.Security.4.0.1\\lib\\net45\\Microsoft.Owin.Security.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Owin.Security.Cookies, Version=4.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Owin.Security.Cookies.4.0.1\\lib\\net45\\Microsoft.Owin.Security.Cookies.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Owin.Security.OAuth, Version=4.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Owin.Security.OAuth.4.0.1\\lib\\net45\\Microsoft.Owin.Security.OAuth.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.Web.Infrastructure.1.0.0.0\\lib\\net40\\Microsoft.Web.Infrastructure.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\MiniProfiler.2.1.0\\lib\\net40\\MiniProfiler.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\MySql.Data.6.9.9\\lib\\net45\\MySql.Data.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Newtonsoft.Json.12.0.2\\lib\\net45\\Newtonsoft.Json.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Ninject, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Ninject.3.2.2.0\\lib\\net45-full\\Ninject.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Ninject.Web.Common, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Ninject.Web.Common.3.2.0.0\\lib\\net45-full\\Ninject.Web.Common.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Ninject.Web.Mvc, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Ninject.MVC3.3.2.1.0\\lib\\net45-full\\Ninject.Web.Mvc.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Nustache.Core, Version=1.16.0.1, Culture=neutral, PublicKeyToken=efd6f3d8f76ecd9f, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Nustache.1.16.0.1\\lib\\net20\\Nustache.Core.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Nustache.Mvc3, Version=1.13.8.22, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Nustache.Mvc3.1.13.8.22\\lib\\net40\\Nustache.Mvc3.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Our.Umbraco.Ditto, Version=0.10.6091.32633, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Our.Umbraco.Ditto.0.10.0\\lib\\net45\\Our.Umbraco.Ditto.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Our.Umbraco.NestedContent, Version=0.3.6033.18955, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Our.Umbraco.NestedContent.0.3.0\\lib\\net45\\Our.Umbraco.NestedContent.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Owin.1.0\\lib\\net40\\Owin.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"RazorEngine, Version=3.4.1.0, Culture=neutral, PublicKeyToken=9ee697374c7e744a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\RazorEngine.3.4.1\\lib\\net45\\RazorEngine.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\semver.1.1.2\\lib\\net451\\Semver.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"SQLCE4Umbraco, Version=1.0.7706.20576, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\SQLCE4Umbraco.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Collections.Immutable, Version=1.1.36.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\System.Collections.Immutable.1.1.36\\lib\\portable-net45+win8+wp8+wpa81\\System.Collections.Immutable.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\System.Data.SqlServerCe.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\System.Data.SqlServerCe.Entity.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Diagnostics.DiagnosticSource, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\System.Diagnostics.DiagnosticSource.4.4.0\\lib\\net45\\System.Diagnostics.DiagnosticSource.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.IO.Compression.FileSystem\" />\n    <Reference Include=\"System.Net.Http\" />\n    <Reference Include=\"System.Net.Http.Formatting, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebApi.Client.5.2.7\\lib\\net45\\System.Net.Http.Formatting.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Reflection.Metadata, Version=1.0.21.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\System.Reflection.Metadata.1.0.21\\lib\\portable-net45+win8\\System.Reflection.Metadata.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"System.Security\" />\n    <Reference Include=\"System.Threading.Tasks.Dataflow, Version=4.6.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\System.Threading.Tasks.Dataflow.4.9.0\\lib\\portable-net45+win8+wpa81\\System.Threading.Tasks.Dataflow.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\System.ValueTuple.4.5.0\\lib\\netstandard1.0\\System.ValueTuple.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.DynamicData\" />\n    <Reference Include=\"System.Web.Entity\" />\n    <Reference Include=\"System.Web.ApplicationServices\" />\n    <Reference Include=\"System.ComponentModel.DataAnnotations\" />\n    <Reference Include=\"System\" />\n    <Reference Include=\"System.Data\" />\n    <Reference Include=\"System.Core\" />\n    <Reference Include=\"System.Data.DataSetExtensions\" />\n    <Reference Include=\"System.Web.Extensions\" />\n    <Reference Include=\"System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebPages.3.2.7\\lib\\net45\\System.Web.Helpers.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.Http, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebApi.Core.5.2.7\\lib\\net45\\System.Web.Http.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.Http.WebHost, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebApi.WebHost.5.2.7\\lib\\net45\\System.Web.Http.WebHost.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.Mvc.5.2.7\\lib\\net45\\System.Web.Mvc.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.Razor.3.2.7\\lib\\net45\\System.Web.Razor.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebPages.3.2.7\\lib\\net45\\System.Web.WebPages.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebPages.3.2.7\\lib\\net45\\System.Web.WebPages.Deployment.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Microsoft.AspNet.WebPages.3.2.7\\lib\\net45\\System.Web.WebPages.Razor.dll</HintPath>\n    </Reference>\n    <Reference Include=\"System.Xml.Linq\" />\n    <Reference Include=\"System.Drawing\" />\n    <Reference Include=\"System.Web\" />\n    <Reference Include=\"System.Xml\" />\n    <Reference Include=\"System.Configuration\" />\n    <Reference Include=\"System.Web.Services\" />\n    <Reference Include=\"System.EnterpriseServices\" />\n    <Reference Include=\"TidyNet, Version=1.0.0.0, Culture=neutral\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\TidyNet.dll</HintPath>\n    </Reference>\n    <Reference Include=\"umbraco, Version=1.0.7706.20577, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\umbraco.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Umbraco.Core, Version=1.0.7706.20570, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\Umbraco.Core.dll</HintPath>\n    </Reference>\n    <Reference Include=\"umbraco.DataLayer, Version=1.0.7706.20574, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\umbraco.DataLayer.dll</HintPath>\n    </Reference>\n    <Reference Include=\"umbraco.editorControls, Version=1.0.7706.20582, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\umbraco.editorControls.dll</HintPath>\n    </Reference>\n    <Reference Include=\"umbraco.MacroEngines, Version=1.0.7706.20582, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\umbraco.MacroEngines.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Umbraco.ModelsBuilder, Version=3.0.10.102, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\Umbraco.ModelsBuilder.3.0.10\\lib\\Umbraco.ModelsBuilder.dll</HintPath>\n    </Reference>\n    <Reference Include=\"umbraco.providers, Version=1.0.7706.20577, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\umbraco.providers.dll</HintPath>\n    </Reference>\n    <Reference Include=\"Umbraco.Web.UI, Version=1.0.7706.20585, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\Umbraco.Web.UI.dll</HintPath>\n    </Reference>\n    <Reference Include=\"UmbracoExamine, Version=0.7.0.20576, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UmbracoCms.Core.7.15.7\\lib\\net452\\UmbracoExamine.dll</HintPath>\n    </Reference>\n    <Reference Include=\"UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\UrlRewritingNet.2.0.7\\lib\\UrlRewritingNet.UrlRewriter.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n    <Reference Include=\"WebActivatorEx, Version=2.0.0.0, Culture=neutral, PublicKeyToken=7b26dc2a43f6a0d4, processorArchitecture=MSIL\">\n      <HintPath>..\\packages\\WebActivatorEx.2.0\\lib\\net40\\WebActivatorEx.dll</HintPath>\n      <Private>True</Private>\n    </Reference>\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\".gitignore\" />\n    <Content Include=\"500.aspx\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\agm-mapprovider.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\agm.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\angular-google-maps.2.1.0.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\angular-google-maps.2.1.0.min.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\angular-google-maps.2.3.3.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\angular-google-maps.2.3.3.min.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\angular-simple-logger.min.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\config.coordinatesbehavour.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\config.defaultlocation.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\config.definition.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\config.format.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\config.icon.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\iconanchorpoint.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\iconsize.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\iconurl.html\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\map-example.png\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\underscore-min.js\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\view.css\" />\n    <Content Include=\"App_Plugins\\AngularGoogleMaps\\2.0.1\\view.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\assets\\logo_50.png\" />\n    <Content Include=\"App_Plugins\\Archetype\\assets\\twitter.png\" />\n    <Content Include=\"App_Plugins\\Archetype\\css\\archetype.css\" />\n    <Content Include=\"App_Plugins\\Archetype\\js\\archetype.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\da-dk.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\da.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\de-de.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\de.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\en-gb.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\en-us.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\en.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\es-es.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\es.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\fr-fr.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\he-il.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\it-it.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\ja-jp.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\ko-kr.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\nb-no.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\nl-nl.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\pl-pl.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\pt-br.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\ru-ru.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\sv-se.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\langs\\zh-cn.js\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.config.developer.dialog.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.config.fieldset.dialog.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.config.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.config.stylescript.dialog.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.default.html\" />\n    <Content Include=\"App_Plugins\\Archetype\\views\\archetype.html\" />\n    <Content Include=\"App_Plugins\\BondOfferDatabaseDownload\\lang\\en-GB.xml\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\detail.html\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\edit.html\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\EditController.js\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\ng-table\\ng-table.min.js\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\tracelog.css\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\readme.txt\" />    \n    <Content Include=\"App_Plugins\\ModelsBuilder\\modelsbuilder.controller.js\" />\n    <Content Include=\"App_Plugins\\ModelsBuilder\\modelsbuilder.htm\" />\n    <Content Include=\"App_Plugins\\ModelsBuilder\\modelsbuilder.resource.js\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Css\\nestedcontent.css\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Js\\nestedcontent.controllers.js\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Js\\nestedcontent.directives.js\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Js\\nestedcontent.resources.js\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Views\\nestedcontent.doctypepicker.html\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Views\\nestedcontent.editor.html\" />\n    <Content Include=\"App_Plugins\\NestedContent\\Views\\nestedcontent.html\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\TheDashboard.controller.js\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\TheDashboard.css\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\TheDashboard.html\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\TheDevDashboard.controller.js\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\TheDevDashboard.html\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\umbraco-guy.png\" />\n    <Content Include=\"App_Plugins\\BondOfferDatabaseDownload\\backoffice\\bondOfferDatabaseDownloadTree\\edit.html\" />\n    <Content Include=\"App_Plugins\\BondOfferDatabaseDownload\\lang\\en-US.xml\" />\n    <Content Include=\"App_Plugins\\uSync\\uSyncDashboard.css\" />\n    <Content Include=\"App_Plugins\\uSync\\uSyncDashboard.html\" />\n    <Content Include=\"App_Plugins\\uSync\\uSyncDashboardController.js\" />\n    <Content Include=\"App_Plugins\\uSync\\uSyncDashboardService.js\" />\n    <Content Include=\"App_Plugins\\uTwit\\js\\uTwit.js\" />\n    <Content Include=\"App_Plugins\\uTwit\\TwitterOAuth1Callback.aspx\" />\n    <Content Include=\"App_Plugins\\uTwit\\views\\uTwit.html\" />\n    <Content Include=\"bin\\TheDashboard.dll\" />\n    <Content Include=\"Client Scripts\\mvcfoolproof.unobtrusive.js\" />\n    <Content Include=\"Client Scripts\\mvcfoolproof.unobtrusive.min.js\" />\n    <Content Include=\"Client Scripts\\MvcFoolproofJQueryValidation.js\" />\n    <Content Include=\"Client Scripts\\MvcFoolproofJQueryValidation.min.js\" />\n    <Content Include=\"Client Scripts\\MvcFoolproofValidation.js\" />\n    <Content Include=\"Client Scripts\\MvcFoolproofValidation.min.js\" />\n    <Content Include=\"Config\\grid.editors.config.js\" />\n    <Content Include=\"Config\\Lang\\cs-CZ.user.xml\" />\n    <Content Include=\"Config\\Lang\\da-DK.user.xml\" />\n    <Content Include=\"Config\\Lang\\de-DE.user.xml\" />\n    <Content Include=\"Config\\Lang\\en-GB.user.xml\" />\n    <Content Include=\"Config\\Lang\\en-US.user.xml\" />\n    <Content Include=\"Config\\Lang\\es-ES.user.xml\" />\n    <Content Include=\"Config\\Lang\\fr-FR.user.xml\" />\n    <Content Include=\"Config\\Lang\\he-IL.user.xml\" />\n    <Content Include=\"Config\\Lang\\it-IT.user.xml\" />\n    <Content Include=\"Config\\Lang\\ja-JP.user.xml\" />\n    <Content Include=\"Config\\Lang\\ko-KR.user.xml\" />\n    <Content Include=\"Config\\Lang\\nb-NO.user.xml\" />\n    <Content Include=\"Config\\Lang\\nl-NL.user.xml\" />\n    <Content Include=\"Config\\Lang\\pl-PL.user.xml\" />\n    <Content Include=\"Config\\Lang\\pt-BR.user.xml\" />\n    <Content Include=\"Config\\Lang\\ru-RU.user.xml\" />\n    <Content Include=\"Config\\Lang\\sv-SE.user.xml\" />\n    <Content Include=\"Config\\Lang\\zh-CN.user.xml\" />\n    <Content Include=\"Config\\UrlRewrites.config\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"Content\\Site.css\" />\n    <Content Include=\"default.aspx\" />\n    <Content Include=\"Global.asax\" />\n    <Content Include=\"gulp\\scripts\\modules\\background-image.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\cookie-notice.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\helpers.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\twitter-timeline.js\" />\n    <Content Include=\"gulp\\scripts\\move\\lite-yt-embed.js\" />\n    <Content Include=\"gulp\\scss\\move\\wysiwyg.css\" />\n    <Content Include=\"Emails\\_signup.html\" />\n    <Content Include=\"favicon.png\" />\n    <Content Include=\"gulpfile.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\banner.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\calc-block.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\external.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\faqs.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\faux-gallery.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\forms.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\icon-tabs.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\map.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\our-history.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\photo-gallery.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\popups.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\projects-map.js\" />\n    <Content Include=\"gulp\\scripts\\modules\\tabs.js\" />\n    <Content Include=\"gulp\\scripts\\mvcfoolproof.unobtrusive.min.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\cookies.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\hogan.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\jquery.bxslider.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\jquery.timeout.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\jquery.validate.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\jquery.validate.unobtrusive.js\" />\n    <Content Include=\"gulp\\scripts\\plugins\\modernizr.js\" />\n    <Content Include=\"gulp\\scripts\\site.js\" />\n    <Content Include=\"gulp\\scss\\modules\\_shares-block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_report-block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_home-feature-block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_content-preview.scss\" />\n    <Content Include=\"App_Plugins\\uTwit\\package.manifest\" />\n    <Content Include=\"gulp\\scss\\modules\\_calc-block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_calc-result.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_help.scss\" />\n    <Content Include=\"Config\\umbracoSettings.config\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"Config\\trees.config\" />\n    <Content Include=\"Config\\ExamineSettings.config\" />\n    <Content Include=\"Config\\ExamineIndex.config\" />\n    <Content Include=\"Config\\Dashboard.config\" />\n    <Content Include=\"Config\\ClientDependency.config\" />\n    <Content Include=\"Config\\applications.config\" />\n    <Content Include=\"gulp\\scss\\modules\\_quick-links.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_help-pin.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_our-history.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_search.scss\" />\n    <Content Include=\"Config\\uSyncCore.Config\" />\n    <Content Include=\"Config\\uSyncBackOffice.Config\" />\n    <Content Include=\"App_Plugins\\uSync\\package.manifest\" />\n    <Content Include=\"gulp\\scss\\modules\\_contact-block.scss\" />\n    <Content Include=\"Emails\\SignUp.mustache\" />\n    <Content Include=\"Emails\\SignUpClientText.mustache\" />\n    <Content Include=\"Emails\\MasterFooter.mustache\" />\n    <Content Include=\"Emails\\MasterHeader.mustache\" />\n    <Content Include=\"gulp\\scss\\modules\\_bond-offer.scss\" />\n    <Content Include=\"Config\\imageprocessor\\security.config\" />\n    <Content Include=\"Config\\imageprocessor\\processing.config\" />\n    <Content Include=\"Config\\imageprocessor\\cache.config\" />\n    <Content Include=\"Config\\log4net.config\" />\n    <Content Include=\"ApplicationInsights.config\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n    <Content Include=\"Connected Services\\Application Insights\\ConnectedService.json\" />\n    <Content Include=\"gulp\\scss\\layout\\_breadcrumbs.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_awards.scss\" />\n    <Content Include=\"App_Plugins\\ModelsBuilder\\package.manifest\" />\n    <Content Include=\"Emails\\SharesRegister.mustache\" />\n    <Content Include=\"App_Code\\ContentHelper.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_alert.scss\" />\n    <Content Include=\"Config\\tinyMceConfig.config\" />\n    <Content Include=\"Config\\scripting.config\" />\n    <Content Include=\"Config\\HealthChecks.config\" />\n    <Content Include=\"Config\\FileSystemProviders.config\" />\n    <Content Include=\"Config\\feedProxy.config\" />\n    <Content Include=\"Config\\EmbeddedMedia.config\" />\n    <Content Include=\"Config\\BaseRestExtensions.config\" />\n    <Content Include=\"Config\\BackOfficeTours\\getting-started.json\" />\n    <Content Include=\"Config\\404handlers.config\" />\n    <Content Include=\"Config\\umbracoSettings.UAT.config\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"Config\\umbracoSettings.LIVE.config\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"gulp\\scss\\modules\\_cookie-notice.scss\" />\n    <None Include=\"gulp\\scss\\modules\\_tweet-block.scss\" />\n    <Content Include=\"images\\common\\loader.gif\" />\n    <Content Include=\"images\\common\\logo-small.png\" />\n    <Content Include=\"images\\common\\logo.png\" />\n    <Content Include=\"images\\common\\sprite.png\" />\n    <Content Include=\"images\\email\\logo.png\" />\n    <Content Include=\"images\\email\\social-facebook.png\" />\n    <Content Include=\"images\\email\\social-linkedin.png\" />\n    <Content Include=\"images\\email\\social-twitter.png\" />\n    <Content Include=\"images\\og\\logo.png\" />\n    <Content Include=\"images\\_temp\\features-2.png\" />\n    <Content Include=\"images\\_temp\\features-3.png\" />\n    <Content Include=\"images\\_temp\\features-1.png\" />\n    <Content Include=\"images\\_temp\\features-4.png\" />\n    <Content Include=\"images\\_temp\\how-tab.png\" />\n    <Content Include=\"packages.config\" />\n    <Content Include=\"robots.txt\" />\n    <Content Include=\"sitemap.xsl\" />\n    <Content Include=\"Views\\Shared\\Pager.cshtml\" />\n    <Content Include=\"Views\\Web.config\" />\n    <Content Include=\"App_Plugins\\NestedContent\\package.manifest\" />\n    <Content Include=\"gulp\\scss\\base\\_config.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_fixes.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_forms.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_helpers.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_print.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_reset.scss\" />\n    <Content Include=\"gulp\\scss\\base\\_version.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_back-to-top.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_content.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_footer.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_nav.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_sub-nav.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_header.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_newsletter.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_page.scss\" />\n    <Content Include=\"gulp\\scss\\layout\\_sitemap.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_grid.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_popups.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_section.scss\" />\n    <Content Include=\"gulp\\scss\\plugins\\_bx-slider.scss\" />\n    <Content Include=\"gulp\\scss\\print.scss\" />\n    <Content Include=\"gulp\\scss\\rte.scss\" />\n    <Content Include=\"gulp\\scss\\site-ie.scss\" />\n    <Content Include=\"gulp\\scss\\site.scss\" />\n    <Content Include=\"gulp\\scss\\_cms.scss\" />\n    <Content Include=\"gulp\\scss\\_config.scss\" />\n    <Content Include=\"gulp\\scss\\_forms.scss\" />\n    <Content Include=\"gulp\\scss\\_reset.scss\" />\n    <Content Include=\"bower.json\" />\n    <Content Include=\"package.json\" />\n    <Content Include=\"App_Plugins\\TheDashboard\\package.manifest\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\package.manifest\" />\n    <Content Include=\"App_Plugins\\DiploTraceLogViewer\\backoffice\\diplotracelog\\ng-table\\ng-table.map\" />\n    <Content Include=\"Views\\Master.cshtml\" />\n    <Content Include=\"Views\\Page.cshtml\" />\n    <Content Include=\"Views\\Sitemap.cshtml\" />\n    <Content Include=\"Views\\Wrapper.cshtml\" />\n    <Content Include=\"Views\\Homepage.cshtml\" />\n    <Content Include=\"Views\\Shared\\Meta.cshtml\" />\n    <Content Include=\"Views\\Shared\\Footer.cshtml\" />\n    <Content Include=\"Views\\Shared\\Header.cshtml\" />\n    <Content Include=\"Views\\Shared\\Navigation.cshtml\" />\n    <Content Include=\"Views\\Error404.cshtml\" />\n    <Content Include=\"Views\\Project.cshtml\" />\n    <Content Include=\"Views\\Projects.cshtml\" />\n    <Content Include=\"Views\\Styleguide.cshtml\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupConfirm.mustache\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupLaunch.mustache\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupVideo.mustache\" />\n    <Content Include=\"Views\\Shared\\NewsletterBlock.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_social.scss\" />\n    <Content Include=\"Views\\Shared\\Features.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_features.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_share.scss\" />\n    <Content Include=\"Views\\Shared\\GridContent.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_banner.scss\" />\n    <Content Include=\"Views\\Shared\\Mustache\\Banner.mustache\" />\n    <Content Include=\"Views\\Shared\\Banner.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_icon-tabs.scss\" />\n    <Content Include=\"Views\\Shared\\Share.cshtml\" />\n    <Content Include=\"Views\\Shared\\SubNavigation.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_promo-block.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_tabs.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_projects-list-item.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_project.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_map.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_faux-gallery.scss\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupGallery.mustache\" />\n    <Content Include=\"Views\\Newsletter.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_projects-map.scss\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupProject.mustache\" />\n    <Content Include=\"gulp\\scss\\modules\\_project-preview.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_photo-gallery.scss\" />\n    <Content Include=\"Views\\Blog.cshtml\" />\n    <Content Include=\"Views\\BlogPost.cshtml\" />\n    <Content Include=\"Views\\FAQs.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_faqs.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_blog.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_pager.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_blog-preview.scss\" />\n    <Content Include=\"Views\\BlogSection.cshtml\" />\n    <Content Include=\"gulp\\scss\\modules\\_blog-post.scss\" />\n    <Content Include=\"gulp\\scss\\modules\\_statement.scss\" />\n    <Content Include=\"Views\\Shared\\NewsFeatures.cshtml\" />\n    <Content Include=\"Views\\Shared\\BlogPreview.cshtml\" />\n    <Content Include=\"Views\\Shared\\BlogNavigation.cshtml\" />\n    <Content Include=\"Views\\Shared\\LatestTweets.cshtml\" />\n    <Content Include=\"Views\\Shared\\TweetList.cshtml\" />\n    <Content Include=\"Views\\Shared\\MoreFeatures.cshtml\" />\n    <Content Include=\"Views\\Shared\\Calculator.cshtml\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupCalcResult.mustache\" />\n    <Content Include=\"Media\\Web.config\" />\n    <Content Include=\"Views\\History.cshtml\" />\n    <Content Include=\"Views\\Shared\\Mustache\\HistoryTimeline.mustache\" />\n    <Content Include=\"Views\\Shared\\Mustache\\PopupSearch.mustache\" />\n    <Content Include=\"Views\\SearchResults.cshtml\" />\n    <Content Include=\"Views\\Shared\\ContactBlock.cshtml\" />\n    <Content Include=\"Views\\Shared\\SharesBlock.cshtml\" />\n    <Content Include=\"Views\\offerSignUpFormDigital.cshtml\" />\n    <Content Include=\"Views\\offerSignUpFormPhysical.cshtml\" />\n    <Content Include=\"Views\\BondOffer.cshtml\" />\n    <Content Include=\"Views\\Shared\\NewsletterBlockSmall.cshtml\" />\n    <Content Include=\"Views\\Shared\\Breadcrumbs.cshtml\" />\n    <Content Include=\"Views\\Shared\\Awards.cshtml\" />\n    <Content Include=\"Views\\SharesRegistrationForm.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Textstring.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Rte.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Media.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Macro.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Embed.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Editors\\Base.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Bootstrap3.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Bootstrap3-Fluid.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Bootstrap2.cshtml\" />\n    <Content Include=\"Views\\Partials\\Grid\\Bootstrap2-Fluid.cshtml\" />\n    <Content Include=\"gulp\\scss\\plugins\\_lite-yt-embed.scss\" />\n    <Content Include=\"Views\\_ViewStart.cshtml\" />\n    <Content Include=\"Views\\Shared\\_Layout.cshtml\" />\n    <Content Include=\"Views\\MasterTextOnly.cshtml\" />\n    <Content Include=\"Views\\SimplePage.cshtml\" />\n    <Content Include=\"Views\\WrapperSimple.cshtml\" />\n    <Content Include=\"Views\\Shared\\CookieNotice.cshtml\" />\n    <None Include=\"Web.Debug.config\">\n      <DependentUpon>Web.config</DependentUpon>\n    </None>\n    <Content Include=\"Web.UAT.config\" />\n    <Content Include=\"Web.LIVE.config\">\n      <SubType>Designer</SubType>\n    </Content>\n    <Content Include=\"Web.Release.config\">\n      <DependentUpon>Web.config</DependentUpon>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <Content Include=\"Web.config\">\n      <SubType>Designer</SubType>\n    </Content>\n  </ItemGroup>\n  <ItemGroup>\n    <Compile Include=\"500.aspx.cs\">\n      <DependentUpon>500.aspx</DependentUpon>\n      <SubType>ASPXCodeBehind</SubType>\n    </Compile>\n    <Compile Include=\"Analyzers\\IgnoreAccentsAnalyzer.cs\" />\n    <Compile Include=\"App_Plugins\\BondOfferDatabaseDownload\\BondOfferDatabaseDownloadController.cs\" />\n    <Compile Include=\"App_Plugins\\BondOfferDatabaseDownload\\BondOfferDatabaseDownloadApplication.cs\" />\n    <Compile Include=\"App_Plugins\\BondOfferDatabaseDownload\\BondOfferDatabaseDownloadTree.cs\" />\n    <Compile Include=\"App_Start\\NinjectWebCommon.cs\" />\n    <Compile Include=\"App_Start\\UmbracoStartup.cs\" />\n    <Compile Include=\"Controllers\\BlogPostController.cs\" />\n    <Compile Include=\"App_Start\\ViewEngineConfig.cs\" />\n    <Compile Include=\"Controllers\\BlogSectionController.cs\" />\n    <Compile Include=\"Controllers\\BondOfferController.cs\" />\n    <Compile Include=\"Controllers\\OfferSignUpFormDigitalController.cs\" />\n    <Compile Include=\"Controllers\\Error404Controller.cs\" />\n    <Compile Include=\"Controllers\\FAQsPageController.cs\" />\n    <Compile Include=\"Controllers\\HistoryController.cs\" />\n    <Compile Include=\"Controllers\\HomeController.cs\" />\n    <Compile Include=\"Controllers\\BlogController.cs\" />\n    <Compile Include=\"Controllers\\NewsletterController.cs\" />\n    <Compile Include=\"Controllers\\OfferSignUpFormPhysicalController.cs\" />\n    <Compile Include=\"Controllers\\ProjectController.cs\" />\n    <Compile Include=\"Controllers\\ProjectsController.cs\" />\n    <Compile Include=\"Controllers\\PageController.cs\" />\n    <Compile Include=\"Controllers\\SearchResultsController.cs\" />\n    <Compile Include=\"Controllers\\SharesRegisterController.cs\" />\n    <Compile Include=\"Controllers\\SimplePageController.cs\" />\n    <Compile Include=\"Controllers\\SitemapController.cs\" />\n    <Compile Include=\"Controllers\\TwitterController.cs\" />\n    <Compile Include=\"ErrorHandler\\AiHandleErrorAttribute.cs\" />\n    <Compile Include=\"FilterConfig.cs\" />\n    <Compile Include=\"Helpers\\ImageExtensions.cs\" />\n    <Compile Include=\"Helpers\\ViewExtensions.cs\" />\n    <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n    <Compile Include=\"RouteHandlers\\RouteHandler.cs\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Folder Include=\"Views\\Export\\\" />\n    <Folder Include=\"Views\\SharesRegister\\\" />\n    <Folder Include=\"Views\\SimplePage\\\" />\n    <Folder Include=\"Views\\UserDatabaseDownload\\\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Analyzer Include=\"..\\packages\\Microsoft.CodeAnalysis.Analyzers.1.0.0\\analyzers\\dotnet\\cs\\Microsoft.CodeAnalysis.Analyzers.dll\" />\n    <Analyzer Include=\"..\\packages\\Microsoft.CodeAnalysis.Analyzers.1.0.0\\analyzers\\dotnet\\cs\\Microsoft.CodeAnalysis.CSharp.Analyzers.dll\" />\n  </ItemGroup>\n  <ItemGroup>\n    <WCFMetadata Include=\"Connected Services\\\" />\n  </ItemGroup>\n  <PropertyGroup>\n    <VisualStudioVersion Condition=\"'$(VisualStudioVersion)' == ''\">10.0</VisualStudioVersion>\n    <VSToolsPath Condition=\"'$(VSToolsPath)' == ''\">$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)</VSToolsPath>\n  </PropertyGroup>\n  <Import Project=\"$(MSBuildBinPath)\\Microsoft.CSharp.targets\" />\n  <Import Project=\"$(VSToolsPath)\\WebApplications\\Microsoft.WebApplication.targets\" Condition=\"'$(VSToolsPath)' != ''\" />\n  <Import Project=\"$(MSBuildExtensionsPath32)\\Microsoft\\VisualStudio\\v10.0\\WebApplications\\Microsoft.WebApplication.targets\" Condition=\"false\" />\n  <ProjectExtensions>\n    <VisualStudio>\n      <FlavorProperties GUID=\"{349c5851-65df-11da-9384-00065b846f21}\">\n        <WebProjectProperties>\n          <UseIIS>True</UseIIS>\n          <AutoAssignPort>True</AutoAssignPort>\n          <DevelopmentServerPort>12088</DevelopmentServerPort>\n          <DevelopmentServerVPath>/</DevelopmentServerVPath>\n          <IISUrl>https://localhost:44333/</IISUrl>\n          <NTLMAuthentication>False</NTLMAuthentication>\n          <UseCustomServer>False</UseCustomServer>\n          <CustomServerUrl>\n          </CustomServerUrl>\n          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>\n        </WebProjectProperties>\n      </FlavorProperties>\n    </VisualStudio>\n  </ProjectExtensions>\n  <Target Name=\"EnsureNuGetPackageBuildImports\" BeforeTargets=\"PrepareForBuild\">\n    <PropertyGroup>\n      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>\n    </PropertyGroup>\n    <Error Condition=\"!Exists('..\\packages\\Microsoft.Net.Compilers.1.0.0\\build\\Microsoft.Net.Compilers.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.Net.Compilers.1.0.0\\build\\Microsoft.Net.Compilers.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\uSync.3.2.2.740\\build\\uSync.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\uSync.3.2.2.740\\build\\uSync.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\uSync.3.2.2.740\\build\\uSync.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\uSync.3.2.2.740\\build\\uSync.targets'))\" />\n    <Error Condition=\"!Exists('..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\\build\\net45\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\\build\\net45\\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.props')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.props'))\" />\n    <Error Condition=\"!Exists('..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.targets')\" Text=\"$([System.String]::Format('$(ErrorText)', '..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.targets'))\" />\n  </Target>\n  <Import Project=\"..\\packages\\uSync.3.2.2.740\\build\\uSync.targets\" Condition=\"Exists('..\\packages\\uSync.3.2.2.740\\build\\uSync.targets')\" />\n  <Import Project=\"..\\packages\\AutoMapper.3.3.1\\tools\\AutoMapper.targets\" Condition=\"Exists('..\\packages\\AutoMapper.3.3.1\\tools\\AutoMapper.targets')\" />\n  <Import Project=\"..\\packages\\OctoPack.3.4.2\\tools\\OctoPack.targets\" Condition=\"Exists('..\\packages\\OctoPack.3.4.2\\tools\\OctoPack.targets')\" />\n  <Target Name=\"EnsureOctoPackImported\" BeforeTargets=\"BeforeBuild\" Condition=\"'$(OctoPackImported)' == ''\">\n    <Error Condition=\"!Exists('..\\packages\\OctoPack.3.4.2\\tools\\OctoPack.targets') And ('$(RunOctoPack)' != '' And $(RunOctoPack))\" Text=\"You are trying to build with OctoPack, but the NuGet targets file that OctoPack depends on is not available on this computer. This is probably because the OctoPack package has not been committed to source control, or NuGet Package Restore is not enabled. Please enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567.\" HelpKeyword=\"BCLBUILD2001\" />\n    <Error Condition=\"Exists('..\\packages\\OctoPack.3.4.2\\tools\\OctoPack.targets') And ('$(RunOctoPack)' != '' And $(RunOctoPack))\" Text=\"OctoPack cannot be run because NuGet packages were restored prior to the build running, and the targets file was unavailable when the build started. Please build the project again to include these packages in the build. You may also need to make sure that your build server does not delete packages prior to each build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568.\" HelpKeyword=\"BCLBUILD2002\" />\n  </Target>\n  <Import Project=\"..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.targets\" Condition=\"Exists('..\\packages\\UmbracoCms.7.15.7\\build\\UmbracoCms.targets')\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "src/test/umbraco/MyProject.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n    <PropertyGroup>\n        <TargetFramework>net7.0</TargetFramework>\n        <ImplicitUsings>enable</ImplicitUsings>\n        <Nullable>enable</Nullable>\n    </PropertyGroup>\n\n    <ItemGroup>\n        <PackageReference Include=\"uMarketingSuite\" Version=\"1.23.0\" />\n        <PackageReference Include=\"Umbraco.TheStarterKit\" Version=\"11.0.0\" />\n        <PackageReference Include=\"Umbraco.Cms\" Version=\"12.1.2\" />\n    </ItemGroup>\n\n    <ItemGroup>\n        <!-- Opt-in to app-local ICU to ensure consistent globalization APIs across different platforms -->\n        <PackageReference Include=\"Microsoft.ICU.ICU4C.Runtime\" Version=\"68.2.0.9\"/>\n        <RuntimeHostConfigurationOption Include=\"System.Globalization.AppLocalIcu\" Value=\"68.2.0.9\" Condition=\"$(RuntimeIdentifier.StartsWith('linux')) or $(RuntimeIdentifier.StartsWith('win')) or ('$(RuntimeIdentifier)' == '' and !$([MSBuild]::IsOSPlatform('osx')))\"/>\n    </ItemGroup>\n\n    <ItemGroup>\n      <ProjectReference Include=\"..\\uMarketingSuite.StarterKit\\uMarketingSuite.StarterKit.csproj\" />\n    </ItemGroup>\n\n    <PropertyGroup>\n        <!-- Razor files are needed for the backoffice to work correctly -->\n        <CopyRazorGenerateFilesToPublishDirectory>true</CopyRazorGenerateFilesToPublishDirectory>\n    </PropertyGroup>\n\n    <PropertyGroup>\n        <!-- Remove RazorCompileOnBuild and RazorCompileOnPublish when not using ModelsMode InMemoryAuto -->\n        <RazorCompileOnBuild>false</RazorCompileOnBuild>\n        <RazorCompileOnPublish>false</RazorCompileOnPublish>\n    </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "src/test/umbraco/web.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n    <!--\n        Define the Web.config template, which is used when creating the initial Web.config,\n        and then transforms from web.Template.[Debug|Release].config are applied.\n        Documentation for Web.config at: https://our.umbraco.com/documentation/Reference/Config/webconfig/\n    -->\n\n    <configSections>\n        <section name=\"clientDependency\" type=\"ClientDependency.Core.Config.ClientDependencySection, ClientDependency.Core\" requirePermission=\"false\"/>\n\n        <sectionGroup name=\"umbracoConfiguration\">\n            <section name=\"settings\" type=\"Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core\" requirePermission=\"false\"/>\n            <section name=\"HealthChecks\" type=\"Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core\" requirePermission=\"false\"/>\n        </sectionGroup>\n\n        <sectionGroup name=\"imageProcessor\">\n            <section name=\"security\" requirePermission=\"false\" type=\"ImageProcessor.Web.Configuration.ImageSecuritySection, ImageProcessor.Web\"/>\n            <section name=\"processing\" requirePermission=\"false\" type=\"ImageProcessor.Web.Configuration.ImageProcessingSection, ImageProcessor.Web\"/>\n            <section name=\"caching\" requirePermission=\"false\" type=\"ImageProcessor.Web.Configuration.ImageCacheSection, ImageProcessor.Web\"/>\n        </sectionGroup>\n    </configSections>\n\n    <umbracoConfiguration>\n        <settings configSource=\"config\\umbracoSettings.config\"/>\n        <HealthChecks configSource=\"config\\HealthChecks.config\"/>\n    </umbracoConfiguration>\n\n    <clientDependency configSource=\"config\\ClientDependency.config\"/>\n\n    <appSettings>\n        <add key=\"Umbraco.Core.ConfigurationStatus\" value=\"8.18.9\"/>\n        <add key=\"Umbraco.Core.ReservedUrls\" value=\"\"/>\n        <add key=\"Umbraco.Core.ReservedPaths\" value=\"\"/>\n        <add key=\"Umbraco.Core.Path\" value=\"~/umbraco\"/>\n        <add key=\"Umbraco.Core.HideTopLevelNodeFromPath\" value=\"true\"/>\n        <add key=\"Umbraco.Core.TimeOutInMinutes\" value=\"20\"/>\n        <add key=\"Umbraco.Core.DefaultUILanguage\" value=\"en-US\"/>\n        <add key=\"Umbraco.Core.UseHttps\" value=\"false\"/>\n        <add key=\"Umbraco.Core.AllowContentDashboardAccessToAllUsers\" value=\"true\"/>\n        <add key=\"Umbraco.Core.ContentDashboardUrl-Allowlist\" value=\"\"/>\n        <add key=\"Umbraco.Core.HelpPage-Allowlist\" value=\"\"/>\n\n        <add key=\"ValidationSettings:UnobtrusiveValidationMode\" value=\"None\"/>\n        <add key=\"webpages:Enabled\" value=\"false\"/>\n        <add key=\"enableSimpleMembership\" value=\"false\"/>\n        <add key=\"autoFormsAuthentication\" value=\"false\"/>\n        <add key=\"dataAnnotations:dataTypeAttribute:disableRegEx\" value=\"false\"/>\n\n        <add key=\"owin:appStartup\" value=\"UmbracoDefaultOwinStartup\"/>\n\n        <add key=\"Umbraco.ModelsBuilder.Enable\" value=\"true\"/>\n        <add key=\"Umbraco.ModelsBuilder.ModelsMode\" value=\"PureLive\"/>\n        <add key=\"Umbraco.Web.PublishedCache.NuCache.Serializer\" value=\"MsgPack\"/>\n        <add key=\"Umbraco.Web.SanitizeTinyMce\" value=\"true\"/>\n    </appSettings>\n\n    <!--\n        Important: if you're upgrading Umbraco, do not clear the connectionString/providerName during your Web.config merge.\n    -->\n    <connectionStrings>\n        <remove name=\"umbracoDbDSN\"/>\n        <add name=\"umbracoDbDSN\" connectionString=\"\" providerName=\"\"/>\n    </connectionStrings>\n\n    <system.data>\n        <DbProviderFactories>\n            <remove invariant=\"System.Data.SqlServerCe.4.0\"/>\n            <add name=\"Microsoft SQL Server Compact Data Provider 4.0\" invariant=\"System.Data.SqlServerCe.4.0\"\n                description=\".NET Framework Data Provider for Microsoft SQL Server Compact\"\n                type=\"System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe\"/>\n        </DbProviderFactories>\n    </system.data>\n\n    <system.net>\n        <mailSettings>\n            <!--\n                If you need Umbraco to send out system mails (like reset password and invite user),\n                you must configure your SMTP settings here - for example:\n            -->\n            <!--\n            <smtp from=\"noreply@example.com\" deliveryMethod=\"Network\">\n                <network host=\"localhost\" port=\"25\" enableSsl=\"false\" userName=\"\" password=\"\" />\n            </smtp>\n            -->\n        </mailSettings>\n    </system.net>\n\n    <system.web>\n        <customErrors mode=\"RemoteOnly\"/>\n\n        <trace enabled=\"false\" requestLimit=\"10\" pageOutput=\"false\" traceMode=\"SortByTime\" localOnly=\"true\"/>\n\n        <httpRuntime requestValidationMode=\"2.0\" enableVersionHeader=\"false\" targetFramework=\"4.7.2\" maxRequestLength=\"51200\" fcnMode=\"Single\"/>\n\n        <httpModules>\n            <add name=\"ScriptModule\"\n                type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>\n            <add name=\"UmbracoModule\" type=\"Umbraco.Web.UmbracoModule,Umbraco.Web\"/>\n            <add name=\"ClientDependencyModule\" type=\"ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core\"/>\n            <add name=\"ImageProcessorModule\" type=\"ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web\"/>\n        </httpModules>\n\n        <httpHandlers>\n            <remove verb=\"*\" path=\"*.asmx\"/>\n            <add verb=\"*\" path=\"*.asmx\"\n                type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"\n                validate=\"false\"/>\n            <add verb=\"*\" path=\"*_AppService.axd\"\n                type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"\n                validate=\"false\"/>\n            <add verb=\"GET,HEAD\" path=\"ScriptResource.axd\"\n                type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"\n                validate=\"false\"/>\n            <add verb=\"*\" path=\"DependencyHandler.axd\" type=\"ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core \"/>\n        </httpHandlers>\n\n        <compilation defaultLanguage=\"c#\" debug=\"false\" batch=\"true\" targetFramework=\"4.7.2\" numRecompilesBeforeAppRestart=\"50\"/>\n\n        <authentication mode=\"Forms\">\n            <forms name=\"yourAuthCookie\" loginUrl=\"login.aspx\" protection=\"All\" path=\"/\"/>\n        </authentication>\n\n        <authorization>\n            <allow users=\"?\"/>\n        </authorization>\n\n        <!-- Membership Provider -->\n        <membership defaultProvider=\"UmbracoMembershipProvider\" userIsOnlineTimeWindow=\"15\">\n            <providers>\n                <clear/>\n                <add name=\"UmbracoMembershipProvider\" type=\"Umbraco.Web.Security.Providers.MembersMembershipProvider, Umbraco.Web\"\n                    minRequiredNonalphanumericCharacters=\"0\" minRequiredPasswordLength=\"10\" useLegacyEncoding=\"false\" enablePasswordRetrieval=\"false\"\n                    enablePasswordReset=\"false\" requiresQuestionAndAnswer=\"false\" defaultMemberTypeAlias=\"Member\" passwordFormat=\"Hashed\"\n                    allowManuallyChangingPassword=\"false\"/>\n                <add name=\"UsersMembershipProvider\" type=\"Umbraco.Web.Security.Providers.UsersMembershipProvider, Umbraco.Web\"/>\n            </providers>\n        </membership>\n\n        <!-- Role Provider -->\n        <roleManager enabled=\"true\" defaultProvider=\"UmbracoRoleProvider\">\n            <providers>\n                <clear/>\n                <add name=\"UmbracoRoleProvider\" type=\"Umbraco.Web.Security.Providers.MembersRoleProvider\"/>\n            </providers>\n        </roleManager>\n\n    </system.web>\n\n    <system.webServer>\n        <validation validateIntegratedModeConfiguration=\"false\"/>\n\n        <modules runAllManagedModulesForAllRequests=\"true\">\n            <remove name=\"WebDAVModule\"/>\n            <remove name=\"UmbracoModule\"/>\n            <remove name=\"ScriptModule\"/>\n            <remove name=\"ClientDependencyModule\"/>\n            <remove name=\"FormsAuthentication\"/>\n            <remove name=\"ImageProcessorModule\"/>\n\n            <add name=\"UmbracoModule\" type=\"Umbraco.Web.UmbracoModule,Umbraco.Web\"/>\n            <add name=\"ScriptModule\" preCondition=\"managedHandler\"\n                type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>\n            <add name=\"ClientDependencyModule\" type=\"ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core\"/>\n            <!-- FormsAuthentication is needed for login/membership to work on homepage (as per http://stackoverflow.com/questions/218057/httpcontext-current-session-is-null-when-routing-requests) -->\n            <add name=\"FormsAuthentication\" type=\"System.Web.Security.FormsAuthenticationModule\"/>\n            <add name=\"ImageProcessorModule\" type=\"ImageProcessor.Web.HttpModules.ImageProcessingModule, ImageProcessor.Web\"/>\n        </modules>\n\n        <handlers accessPolicy=\"Read, Write, Script, Execute\">\n            <remove name=\"WebServiceHandlerFactory-Integrated\"/>\n            <remove name=\"ScriptHandlerFactory\"/>\n            <remove name=\"ScriptHandlerFactoryAppServices\"/>\n            <remove name=\"ScriptResource\"/>\n            <remove name=\"ClientDependency\"/>\n            <remove name=\"MiniProfiler\"/>\n            <remove name=\"ExtensionlessUrlHandler-Integrated-4.0\"/>\n            <remove name=\"OPTIONSVerbHandler\"/>\n            <remove name=\"TRACEVerbHandler\"/>\n\n            <add name=\"ScriptHandlerFactory\" verb=\"*\" path=\"*.asmx\" preCondition=\"integratedMode\"\n                type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>\n            <add name=\"ScriptHandlerFactoryAppServices\" verb=\"*\" path=\"*_AppService.axd\" preCondition=\"integratedMode\"\n                type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>\n            <add name=\"ScriptResource\" verb=\"GET,HEAD\" path=\"ScriptResource.axd\" preCondition=\"integratedMode\"\n                type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\"/>\n            <add verb=\"*\" name=\"ClientDependency\" preCondition=\"integratedMode\" path=\"DependencyHandler.axd\"\n                type=\"ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core\"/>\n            <add name=\"MiniProfiler\" path=\"mini-profiler-resources/*\" verb=\"*\" type=\"System.Web.Routing.UrlRoutingModule\" resourceType=\"Unspecified\"\n                preCondition=\"integratedMode\"/>\n            <add name=\"ExtensionlessUrlHandler-Integrated-4.0\" path=\"*.\" verb=\"*\" type=\"System.Web.Handlers.TransferRequestHandler\"\n                preCondition=\"integratedMode,runtimeVersionv4.0\"/>\n        </handlers>\n\n        <staticContent>\n            <remove fileExtension=\".air\"/>\n            <mimeMap fileExtension=\".air\" mimeType=\"application/vnd.adobe.air-application-installer-package+zip\"/>\n            <remove fileExtension=\".svg\"/>\n            <mimeMap fileExtension=\".svg\" mimeType=\"image/svg+xml\"/>\n            <remove fileExtension=\".woff\"/>\n            <mimeMap fileExtension=\".woff\" mimeType=\"font/woff\"/>\n            <remove fileExtension=\".woff2\"/>\n            <mimeMap fileExtension=\".woff2\" mimeType=\"font/woff2\"/>\n            <remove fileExtension=\".less\"/>\n            <mimeMap fileExtension=\".less\" mimeType=\"text/css\"/>\n            <remove fileExtension=\".mp4\"/>\n            <mimeMap fileExtension=\".mp4\" mimeType=\"video/mp4\"/>\n            <remove fileExtension=\".json\"/>\n            <mimeMap fileExtension=\".json\" mimeType=\"application/json\"/>\n        </staticContent>\n\n        <!-- Ensure the powered by header is not returned -->\n        <httpProtocol>\n            <customHeaders>\n                <remove name=\"X-Powered-By\"/>\n            </customHeaders>\n        </httpProtocol>\n\n        <!-- Increase the default upload file size limit -->\n        <security>\n            <requestFiltering>\n                <requestLimits maxAllowedContentLength=\"52428800\"/>\n            </requestFiltering>\n        </security>\n\n        <!--\n            If you wish to use IIS rewrite rules, see the documentation here: https://our.umbraco.com/documentation/Reference/Routing/IISRewriteRules\n        -->\n        <!--\n        <rewrite>\n            <rules></rules>\n        </rewrite>\n        -->\n    </system.webServer>\n\n    <runtime>\n        <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n            <dependentAssembly>\n                <assemblyIdentity name=\"Microsoft.Owin\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.1.0\" newVersion=\"4.0.1.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"Microsoft.Owin.Security\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.1.0\" newVersion=\"4.0.1.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"Microsoft.Owin.Security.Cookies\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.1.0\" newVersion=\"4.0.1.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"Microsoft.Owin.Security.OAuth\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.1.0\" newVersion=\"4.0.1.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"Newtonsoft.Json\" publicKeyToken=\"30ad4fe6b2a6aeed\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-12.0.0.0\" newVersion=\"12.0.0.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Collections.Immutable\" publicKeyToken=\"b03f5f7f11d50a3a\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-1.2.5.0\" newVersion=\"1.2.5.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Web.Http\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-5.2.7.0\" newVersion=\"5.2.7.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Web.Mvc\" publicKeyToken=\"31bf3856ad364e35\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-5.2.7.0\" newVersion=\"5.2.7.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.ValueTuple\" publicKeyToken=\"cc7b13ffcd2ddd51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.3.0\" newVersion=\"4.0.3.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Net.Http.Formatting\" publicKeyToken=\"31bf3856ad364e35\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-5.2.7.0\" newVersion=\"5.2.7.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Runtime.CompilerServices.Unsafe\" publicKeyToken=\"b03f5f7f11d50a3a\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"0.0.0.0-4.0.6.0\" newVersion=\"4.0.6.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Buffers\" publicKeyToken=\"cc7b13ffcd2ddd51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"4.0.0.0-4.0.3.0\" newVersion=\"4.0.3.0\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Memory\" publicKeyToken=\"cc7b13ffcd2ddd51\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"4.0.0.0-4.0.1.1\" newVersion=\"4.0.1.1\"/>\n            </dependentAssembly>\n            <dependentAssembly>\n                <assemblyIdentity name=\"System.Numerics.Vectors\" publicKeyToken=\"b03f5f7f11d50a3a\" culture=\"neutral\"/>\n                <bindingRedirect oldVersion=\"4.0.0.0-4.1.4.0\" newVersion=\"4.1.4.0\"/>\n            </dependentAssembly>\n        </assemblyBinding>\n    </runtime>\n\n    <location path=\"umbraco\">\n        <system.webServer>\n            <urlCompression doStaticCompression=\"false\" doDynamicCompression=\"false\" dynamicCompressionBeforeCache=\"false\"/>\n        </system.webServer>\n    </location>\n    <location path=\"App_Plugins\">\n        <system.webServer>\n            <urlCompression doStaticCompression=\"false\" doDynamicCompression=\"false\" dynamicCompressionBeforeCache=\"false\"/>\n        </system.webServer>\n    </location>\n\n    <imageProcessor>\n        <security configSource=\"config\\imageprocessor\\security.config\"/>\n        <caching configSource=\"config\\imageprocessor\\cache.config\"/>\n        <processing configSource=\"config\\imageprocessor\\processing.config\"/>\n    </imageProcessor>\n\n    <system.codedom>\n        <compilers>\n            <compiler language=\"c#;cs;csharp\" extension=\".cs\"\n                type=\"Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"\n                warningLevel=\"4\" compilerOptions=\"/langversion:7 /nowarn:1659;1699;1701\"/>\n            <compiler language=\"vb;vbs;visualbasic;vbscript\" extension=\".vb\"\n                type=\"Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"\n                warningLevel=\"4\" compilerOptions=\"/langversion:14 /nowarn:41008 /define:_MYTYPE=\\&quot;Web\\&quot; /optionInfer+\"/>\n        </compilers>\n    </system.codedom>\n\n</configuration>\n"
  },
  {
    "path": "src/test/umbraco/web.old.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <configSections>\n    <section name=\"urlrewritingnet\" restartOnExternalChanges=\"true\" requirePermission=\"false\" type=\"UrlRewritingNet.Configuration.UrlRewriteSection, UrlRewritingNet.UrlRewriter\" />\n    <section name=\"microsoft.scripting\" type=\"Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\" requirePermission=\"false\" />\n    <section name=\"clientDependency\" type=\"ClientDependency.Core.Config.ClientDependencySection, ClientDependency.Core\" requirePermission=\"false\" />\n    <section name=\"Examine\" type=\"Examine.Config.ExamineSettings, Examine\" requirePermission=\"false\" />\n    <section name=\"ExamineLuceneIndexSets\" type=\"UmbracoExamine.Config.ExamineLuceneIndexes, UmbracoExamine\" requirePermission=\"false\" />\n    <section name=\"FileSystemProviders\" type=\"Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core\" requirePermission=\"false\" />\n    <section name=\"log4net\" type=\"log4net.Config.Log4NetConfigurationSectionHandler, log4net\" requirePermission=\"false\" />\n    <section name=\"BaseRestExtensions\" type=\"Umbraco.Web.BaseRest.Configuration.BaseRestSection, umbraco\" requirePermission=\"false\" />\n    <sectionGroup name=\"system.web.webPages.razor\" type=\"System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\">\n      <section name=\"host\" type=\"System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" />\n      <section name=\"pages\" type=\"System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" requirePermission=\"false\" />\n    </sectionGroup>\n  </configSections>\n  <urlrewritingnet configSource=\"config\\UrlRewriting.config\" />\n  <microsoft.scripting configSource=\"config\\scripting.config\" />\n  <clientDependency configSource=\"config\\ClientDependency.config\" />\n  <Examine configSource=\"config\\ExamineSettings.config\" />\n  <ExamineLuceneIndexSets configSource=\"config\\ExamineIndex.config\" />\n  <FileSystemProviders configSource=\"config\\FileSystemProviders.config\" />\n  <log4net configSource=\"config\\log4net.config\" />\n  <BaseRestExtensions configSource=\"config\\BaseRestExtensions.config\" />\n  <appSettings>\n    <add key=\"umbracoDbDSN\" value=\"datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;data source=|DataDirectory|\\Umbraco.sdf\" />\n    <add key=\"umbracoConfigurationStatus\" value=\"4.11.10\" />\n    <add key=\"umbracoReservedUrls\" value=\"~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd\" />\n    <add key=\"umbracoReservedPaths\" value=\"~/umbraco,~/install/\" />\n    <add key=\"umbracoContentXML\" value=\"~/App_Data/umbraco.config\" />\n    <add key=\"umbracoStorageDirectory\" value=\"~/App_Data\" />\n    <add key=\"umbracoPath\" value=\"~/umbraco\" />\n    <add key=\"umbracoEnableStat\" value=\"false\" />\n    <add key=\"umbracoHideTopLevelNodeFromPath\" value=\"true\" />\n    <add key=\"umbracoEditXhtmlMode\" value=\"true\" />\n    <add key=\"umbracoUseDirectoryUrls\" value=\"false\" />\n    <add key=\"umbracoDebugMode\" value=\"false\" />\n    <add key=\"umbracoTimeOutInMinutes\" value=\"20\" />\n    <add key=\"umbracoVersionCheckPeriod\" value=\"7\" />\n    <add key=\"umbracoDisableXsltExtensions\" value=\"true\" />\n    <add key=\"umbracoDefaultUILanguage\" value=\"en\" />\n    <add key=\"umbracoProfileUrl\" value=\"profiler\" />\n    <add key=\"umbracoUseSSL\" value=\"false\" />\n    <add key=\"umbracoUseMediumTrust\" value=\"false\" />\n    <!-- Set this to true to enable storing the xml cache locally to the IIS server even if the app files are stored centrally on a SAN/NAS Alex Norcliffe 2010 02 for 4.1  -->\n    <add key=\"umbracoContentXMLUseLocalTemp\" value=\"false\" />\n    <add key=\"webpages:Enabled\" value=\"false\" />\n    <add key=\"enableSimpleMembership\" value=\"false\" />\n    <add key=\"autoFormsAuthentication\" value=\"false\" />\n    <add key=\"log4net.Config\" value=\"config\\log4net.config\" />\n  </appSettings>\n  <system.net>\n    <mailSettings>\n      <smtp>\n        <network host=\"127.0.0.1\" userName=\"username\" password=\"password\" />\n      </smtp>\n    </mailSettings>\n  </system.net>\n  <connectionStrings>\n    <remove name=\"LocalSqlServer\" />\n    <!--<add name=\"LocalSqlServer\" connectionString=\"server=.\\sqlexpress;database=aspnetdb;user id=DBUSER;password=DBPASSWORD\" providerName=\"System.Data.SqlClient\"/>-->\n  </connectionStrings>\n  <system.web>\n    <customErrors mode=\"RemoteOnly\" />\n    <trace enabled=\"false\" requestLimit=\"10\" pageOutput=\"false\" traceMode=\"SortByTime\" localOnly=\"true\" />\n    <sessionState mode=\"InProc\" stateConnectionString=\"tcpip=127.0.0.1:42424\" sqlConnectionString=\"data source=127.0.0.1;Trusted_Connection=yes\" cookieless=\"false\" timeout=\"20\" />\n    <globalization requestEncoding=\"UTF-8\" responseEncoding=\"UTF-8\" />\n    <xhtmlConformance mode=\"Strict\" />\n    <httpRuntime requestValidationMode=\"2.0\" enableVersionHeader=\"false\" />\n    <pages enableEventValidation=\"false\">\n      <!-- ASPNETAJAX -->\n      <controls>\n        <add tagPrefix=\"asp\" namespace=\"System.Web.UI\" assembly=\"System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add tagPrefix=\"umbraco\" namespace=\"umbraco.presentation.templateControls\" assembly=\"umbraco\" />\n        <add tagPrefix=\"asp\" namespace=\"System.Web.UI.WebControls\" assembly=\"System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      </controls>\n    </pages>\n    <httpModules>\n      <!-- URL REWRTIER -->\n      <add name=\"UrlRewriteModule\" type=\"UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter\" />\n      <!-- UMBRACO -->\n      <add name=\"UmbracoModule\" type=\"Umbraco.Web.UmbracoModule,umbraco\" />\n      <!-- ASPNETAJAX -->\n      <add name=\"ScriptModule\" type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      <!-- CLIENT DEPENDENCY -->\n      <add name=\"ClientDependencyModule\" type=\"ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core\" />\n    </httpModules>\n    <httpHandlers>\n      <remove verb=\"*\" path=\"*.asmx\" />\n      <!-- ASPNETAJAX -->\n      <add verb=\"*\" path=\"*.asmx\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" validate=\"false\" />\n      <add verb=\"*\" path=\"*_AppService.axd\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" validate=\"false\" />\n      <add verb=\"GET,HEAD\" path=\"ScriptResource.axd\" type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" validate=\"false\" />\n      <!-- UMBRACO CHANNELS -->\n      <add verb=\"*\" path=\"umbraco/channels.aspx\" type=\"umbraco.presentation.channels.api, umbraco\" />\n      <add verb=\"*\" path=\"umbraco/channels/word.aspx\" type=\"umbraco.presentation.channels.wordApi, umbraco\" />\n      <!-- CLIENT DEPENDENCY -->\n      <add verb=\"*\" path=\"DependencyHandler.axd\" type=\"ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core \" />\n      <!-- SPELL CHECKER -->\n      <add verb=\"GET,HEAD,POST\" path=\"GoogleSpellChecker.ashx\" type=\"umbraco.presentation.umbraco_client.tinymce3.plugins.spellchecker.GoogleSpellChecker,umbraco\" />\n    </httpHandlers>\n    <compilation defaultLanguage=\"c#\" debug=\"false\" batch=\"false\" targetFramework=\"4.0\">\n      <assemblies>\n        <!-- ASP.NET 4.0 Assemblies -->\n        <add assembly=\"System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A\" />\n        <add assembly=\"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\" />\n        <add assembly=\"System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\" />\n        <add assembly=\"System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089\" />\n        <add assembly=\"System.Web.Extensions.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n        <add assembly=\"System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      </assemblies>\n      <buildProviders>\n        <add extension=\".cshtml\" type=\"umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines\" />\n        <add extension=\".vbhtml\" type=\"umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines\" />\n        <add extension=\".razor\" type=\"umbraco.MacroEngines.RazorBuildProvider, umbraco.MacroEngines\" />\n      </buildProviders>\n    </compilation>\n    <authentication mode=\"Forms\">\n      <forms name=\"yourAuthCookie\" loginUrl=\"login.aspx\" protection=\"All\" path=\"/\" />\n    </authentication>\n    <authorization>\n      <allow users=\"?\" />\n    </authorization>\n    <!-- Membership Provider -->\n    <membership defaultProvider=\"UmbracoMembershipProvider\" userIsOnlineTimeWindow=\"15\">\n      <providers>\n        <clear />\n        <add name=\"UmbracoMembershipProvider\" type=\"umbraco.providers.members.UmbracoMembershipProvider\" enablePasswordRetrieval=\"false\" enablePasswordReset=\"false\" requiresQuestionAndAnswer=\"false\" defaultMemberTypeAlias=\"Another Type\" passwordFormat=\"Hashed\" />\n        <add name=\"UsersMembershipProvider\" type=\"umbraco.providers.UsersMembershipProvider\" enablePasswordRetrieval=\"false\" enablePasswordReset=\"false\" requiresQuestionAndAnswer=\"false\" passwordFormat=\"Hashed\" />\n      </providers>\n    </membership>\n    <!-- added by NH to support membership providers in access layer -->\n    <roleManager enabled=\"true\" defaultProvider=\"UmbracoRoleProvider\">\n      <providers>\n        <clear />\n        <add name=\"UmbracoRoleProvider\" type=\"umbraco.providers.members.UmbracoRoleProvider\" />\n      </providers>\n    </roleManager>\n    <!-- Sitemap provider-->\n    <siteMap defaultProvider=\"UmbracoSiteMapProvider\" enabled=\"true\">\n      <providers>\n        <clear />\n        <add name=\"UmbracoSiteMapProvider\" type=\"umbraco.presentation.nodeFactory.UmbracoSiteMapProvider\" defaultDescriptionAlias=\"description\" securityTrimmingEnabled=\"true\" />\n      </providers>\n    </siteMap>\n  </system.web>\n  <!-- ASPNETAJAX -->\n  <system.web.extensions>\n    <scripting>\n      <scriptResourceHandler enableCompression=\"true\" enableCaching=\"true\" />\n    </scripting>\n  </system.web.extensions>\n  <system.webServer>\n    <validation validateIntegratedModeConfiguration=\"false\" />\n    <modules runAllManagedModulesForAllRequests=\"true\">\n      <remove name=\"UrlRewriteModule\" />\n      <add name=\"UrlRewriteModule\" type=\"UrlRewritingNet.Web.UrlRewriteModule, UrlRewritingNet.UrlRewriter\" />\n      <remove name=\"UmbracoModule\" />\n      <add name=\" UmbracoModule\" type=\"Umbraco.Web.UmbracoModule,umbraco\" />\n      <remove name=\"ScriptModule\" />\n      <add name=\"ScriptModule\" preCondition=\"managedHandler\" type=\"System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      <remove name=\"ClientDependencyModule\" />\n      <add name=\"ClientDependencyModule\" type=\"ClientDependency.Core.Module.ClientDependencyModule, ClientDependency.Core\" />\n      <!-- Needed for login/membership to work on homepage (as per http://stackoverflow.com/questions/218057/httpcontext-current-session-is-null-when-routing-requests) -->\n      <remove name=\"FormsAuthentication\" />\n      <add name=\"FormsAuthentication\" type=\"System.Web.Security.FormsAuthenticationModule\" />\n    </modules>\n    <handlers accessPolicy=\"Read, Write, Script, Execute\">\n      <remove name=\"WebServiceHandlerFactory-Integrated\" />\n      <remove name=\"ScriptHandlerFactory\" />\n      <remove name=\"ScriptHandlerFactoryAppServices\" />\n      <remove name=\"ScriptResource\" />\n      <remove name=\"Channels\" />\n      <remove name=\"Channels_Word\" />\n      <remove name=\"ClientDependency\" />\n      <remove name=\"SpellChecker\" />\n      <add name=\"ScriptHandlerFactory\" verb=\"*\" path=\"*.asmx\" preCondition=\"integratedMode\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      <add name=\"ScriptHandlerFactoryAppServices\" verb=\"*\" path=\"*_AppService.axd\" preCondition=\"integratedMode\" type=\"System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      <add name=\"ScriptResource\" verb=\"GET,HEAD\" path=\"ScriptResource.axd\" preCondition=\"integratedMode\" type=\"System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35\" />\n      <add verb=\"*\" name=\"Channels\" preCondition=\"integratedMode\" path=\"umbraco/channels.aspx\" type=\"umbraco.presentation.channels.api, umbraco\" />\n      <add verb=\"*\" name=\"Channels_Word\" preCondition=\"integratedMode\" path=\"umbraco/channels/word.aspx\" type=\"umbraco.presentation.channels.wordApi, umbraco\" />\n      <add verb=\"*\" name=\"ClientDependency\" preCondition=\"integratedMode\" path=\"DependencyHandler.axd\" type=\"ClientDependency.Core.CompositeFiles.CompositeDependencyHandler, ClientDependency.Core \" />\n      <add verb=\"GET,HEAD,POST\" preCondition=\"integratedMode\" name=\"SpellChecker\" path=\"GoogleSpellChecker.ashx\" type=\"umbraco.presentation.umbraco_client.tinymce3.plugins.spellchecker.GoogleSpellChecker,umbraco\" />\n    </handlers>\n    <!-- Adobe AIR mime type -->\n    <staticContent>\n      <remove fileExtension=\".air\" />\n      <mimeMap fileExtension=\".air\" mimeType=\"application/vnd.adobe.air-application-installer-package+zip\" />\n    </staticContent>\n    <!-- Ensure the powered by header is not returned -->\n    <httpProtocol>\n      <customHeaders>\n        <remove name=\"X-Powered-By\" />\n      </customHeaders>\n    </httpProtocol>\n  </system.webServer>\n  <system.codedom>\n    <compilers>\n      <compiler language=\"c#;cs;csharp\" extension=\".cs\" type=\"Microsoft.CSharp.CSharpCodeProvider,System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\" warningLevel=\"4\">\n        <providerOption name=\"CompilerVersion\" value=\"v4.0\" />\n        <providerOption name=\"WarnAsError\" value=\"false\" />\n      </compiler>\n    </compilers>\n  </system.codedom>\n  <runtime>\n    <!-- Old asp.net ajax assembly bindings -->\n    <assemblyBinding xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n      <dependentAssembly>\n        <assemblyIdentity name=\"System.Web.Extensions\" publicKeyToken=\"31bf3856ad364e35\" />\n        <bindingRedirect oldVersion=\"1.0.0.0-1.1.0.0\" newVersion=\"4.0.0.0\" />\n      </dependentAssembly>\n      <dependentAssembly>\n        <assemblyIdentity name=\"System.Web.Extensions.Design\" publicKeyToken=\"31bf3856ad364e35\" />\n        <bindingRedirect oldVersion=\"1.0.0.0-1.1.0.0\" newVersion=\"4.0.0.0\" />\n      </dependentAssembly>\n    </assemblyBinding>\n  </runtime>\n  <system.web.webPages.razor>\n    <host factoryType=\"umbraco.MacroEngines.RazorUmbracoFactory, umbraco.MacroEngines\" />\n    <pages pageBaseType=\"umbraco.MacroEngines.DynamicNodeContext\">\n      <namespaces>\n        <add namespace=\"Microsoft.Web.Helpers\" />\n        <add namespace=\"umbraco\" />\n        <add namespace=\"Examine\" />\n      </namespaces>\n    </pages>\n  </system.web.webPages.razor>\n</configuration>"
  },
  {
    "path": "src/test/valid.nuspec",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<package xmlns=\"http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd\">\n  <metadata>\n    <id>Az.Compute</id>\n    <title>Az.Compute</title>\n    <version>0.1.0</version>\n    <authors>Microsoft Corporation</authors>\n    <owners>Microsoft Corporation</owners>\n    <requireLicenseAcceptance>true</requireLicenseAcceptance>\n    <licenseUrl>https://aka.ms/azps-license</licenseUrl>\n    <projectUrl>https://github.com/Azure/azure-powershell</projectUrl>\n    <description>Microsoft Azure PowerShell: $(service-name) cmdlets</description>\n    <releaseNotes></releaseNotes>\n    <copyright>Microsoft Corporation. All rights reserved.</copyright>\n    <tags>Azure ResourceManager ARM PSModule $(service-name)</tags>\n    <dependencies>\n      <dependency id=\"Az.Accounts\" version=\"2.2.3\" />\n    </dependencies>\n  </metadata>\n  <files>\n    <file src=\"Az.Compute.format.ps1xml\" />\n    <file src=\"Az.Compute.psd1\" />\n    <file src=\"Az.Compute.psm1\" />\n    <!-- https://github.com/NuGet/Home/issues/3584 -->\n    <file src=\"bin/Az.Compute.private.dll\" target=\"bin\" />\n    <file src=\"bin\\Az.Compute.private.deps.json\" target=\"bin\" />\n    <file src=\"internal\\**\\*.*\" exclude=\"internal\\README.md\" target=\"internal\" />\n    <file src=\"custom\\**\\*.*\" exclude=\"custom\\README.md;custom\\**\\*.cs\" target=\"custom\" />\n    <file src=\"docs\\**\\*.md\" exclude=\"docs\\README.md\" target=\"docs\" />\n    <file src=\"exports\\**\\ProxyCmdletDefinitions.ps1\" target=\"exports\" />\n    <file src=\"utils\\**\\*.*\" target=\"utils\" />\n  </files>\n</package>\n"
  },
  {
    "path": "src/test/versions.tf",
    "content": "terraform {\n  required_version = \">= 1.0.10\"\n}\n"
  },
  {
    "path": "src/text/builder.go",
    "content": "package text\n\nimport (\n\t\"strings\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/generics\"\n)\n\nvar builderPool *generics.Pool[*StringBuilder]\n\ntype StringBuilder strings.Builder\n\nfunc init() {\n\tbuilderPool = generics.NewPool(func() *StringBuilder {\n\t\treturn &StringBuilder{}\n\t})\n}\n\n// NewBuilder returns a StringBuilder from the pool\nfunc NewBuilder() *StringBuilder {\n\treturn builderPool.Get()\n}\n\nfunc (sb *StringBuilder) release() {\n\tif sb == nil {\n\t\treturn\n\t}\n\n\t// Reset the StringBuilder to clear its content\n\t(*strings.Builder)(sb).Reset()\n\tbuilderPool.Put(sb)\n}\n\n// String returns the accumulated string.\nfunc (sb *StringBuilder) String() string {\n\ttext := (*strings.Builder)(sb).String()\n\tsb.release()\n\treturn text\n}\n\n// Len returns the number of accumulated bytes; b.Len() == len(b.String()).\nfunc (sb *StringBuilder) Len() int {\n\treturn (*strings.Builder)(sb).Len()\n}\n\n// Cap returns the capacity of the builder's underlying byte slice. It is the\n// total space allocated for the string being built and includes any bytes\n// already written.\nfunc (sb *StringBuilder) Cap() int {\n\treturn (*strings.Builder)(sb).Cap()\n}\n\n// Reset resets the Builder to be empty.\nfunc (sb *StringBuilder) Reset() {\n\t(*strings.Builder)(sb).Reset()\n}\n\n// Grow grows b's capacity, if necessary, to guarantee space for\n// another n bytes. After Grow(n), at least n bytes can be written to b\n// without another allocation. If n is negative, Grow panics.\nfunc (sb *StringBuilder) Grow(n int) {\n\t(*strings.Builder)(sb).Grow(n)\n}\n\n// WriteRune appends the UTF-8 encoding of Unicode code point r to b's buffer.\nfunc (sb *StringBuilder) WriteRune(r rune) {\n\t_, _ = (*strings.Builder)(sb).WriteRune(r)\n}\n\n// WriteString appends the contents of s to b's buffer.\nfunc (sb *StringBuilder) WriteString(s string) {\n\t_, _ = (*strings.Builder)(sb).WriteString(s)\n}\n"
  },
  {
    "path": "src/text/percentage.go",
    "content": "package text\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Percentage represents a percentage value with gauge visualization.\ntype Percentage int\n\n// clamp ensures the percentage value is within the valid range of 0-100.\nfunc (p Percentage) clamp() int {\n\treturn min(max(int(p), 0), 100)\n}\n\n// Gauge returns a 5-character gauge visualization showing remaining capacity (▰▰▰▰▱ style).\n// The gauge displays remaining capacity, so 20% used shows 4 filled blocks (80% remaining).\nfunc (p Percentage) Gauge() string {\n\tpercent := p.clamp()\n\n\t// Calculate remaining percentage for gauge display\n\tremainingPercent := 100 - percent\n\n\t// 5 blocks total, calculate how many should be filled (representing remaining capacity)\n\tfilledBlocks := (remainingPercent * 5) / 100\n\temptyBlocks := 5 - filledBlocks\n\n\t// Use ▰ for filled blocks (remaining) and ▱ for empty blocks (used)\n\treturn strings.Repeat(\"▰\", filledBlocks) + strings.Repeat(\"▱\", emptyBlocks)\n}\n\n// GaugeUsed returns a 5-character gauge visualization showing used capacity (▰▱▱▱▱ style).\n// The gauge displays used capacity, so 20% used shows 1 filled block (▰▱▱▱▱).\nfunc (p Percentage) GaugeUsed() string {\n\tpercent := p.clamp()\n\n\t// 5 blocks total, calculate how many should be filled (representing used capacity)\n\tfilledBlocks := (percent * 5) / 100\n\temptyBlocks := 5 - filledBlocks\n\n\t// Use ▰ for filled blocks (used) and ▱ for empty blocks (remaining)\n\treturn strings.Repeat(\"▰\", filledBlocks) + strings.Repeat(\"▱\", emptyBlocks)\n}\n\n// String returns the percentage as a string without % sign for template compatibility.\nfunc (p Percentage) String() string {\n\treturn fmt.Sprintf(\"%d\", int(p))\n}\n"
  },
  {
    "path": "src/text/percentage_test.go",
    "content": "package text\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\n//nolint:dupl\nfunc TestPercentageGauge(t *testing.T) {\n\tcases := []struct {\n\t\tCase          string\n\t\tExpectedGauge string\n\t\tPercent       Percentage\n\t}{\n\t\t{\n\t\t\tCase:          \"0 percent used (100% remaining)\",\n\t\t\tPercent:       Percentage(0),\n\t\t\tExpectedGauge: \"▰▰▰▰▰\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"20 percent used (80% remaining - 4 blocks)\",\n\t\t\tPercent:       Percentage(20),\n\t\t\tExpectedGauge: \"▰▰▰▰▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"40 percent used (60% remaining - 3 blocks)\",\n\t\t\tPercent:       Percentage(40),\n\t\t\tExpectedGauge: \"▰▰▰▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"60 percent used (40% remaining - 2 blocks)\",\n\t\t\tPercent:       Percentage(60),\n\t\t\tExpectedGauge: \"▰▰▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"80 percent used (20% remaining - 1 block)\",\n\t\t\tPercent:       Percentage(80),\n\t\t\tExpectedGauge: \"▰▱▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"100 percent used (0% remaining - 0 blocks)\",\n\t\t\tPercent:       Percentage(100),\n\t\t\tExpectedGauge: \"▱▱▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"50 percent used (50% remaining - 2.5 rounds to 2 blocks)\",\n\t\t\tPercent:       Percentage(50),\n\t\t\tExpectedGauge: \"▰▰▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Negative percent clamps to 0\",\n\t\t\tPercent:       Percentage(-10),\n\t\t\tExpectedGauge: \"▰▰▰▰▰\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Over 100 percent clamps to 100\",\n\t\t\tPercent:       Percentage(120),\n\t\t\tExpectedGauge: \"▱▱▱▱▱\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tresult := tc.Percent.Gauge()\n\t\t\tassert.Equal(t, tc.ExpectedGauge, result, tc.Case)\n\t\t})\n\t}\n}\n\n//nolint:dupl\nfunc TestPercentageGaugeUsed(t *testing.T) {\n\tcases := []struct {\n\t\tCase          string\n\t\tExpectedGauge string\n\t\tPercent       Percentage\n\t}{\n\t\t{\n\t\t\tCase:          \"0 percent used\",\n\t\t\tPercent:       Percentage(0),\n\t\t\tExpectedGauge: \"▱▱▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"20 percent used\",\n\t\t\tPercent:       Percentage(20),\n\t\t\tExpectedGauge: \"▰▱▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"40 percent used\",\n\t\t\tPercent:       Percentage(40),\n\t\t\tExpectedGauge: \"▰▰▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"60 percent used\",\n\t\t\tPercent:       Percentage(60),\n\t\t\tExpectedGauge: \"▰▰▰▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"80 percent used\",\n\t\t\tPercent:       Percentage(80),\n\t\t\tExpectedGauge: \"▰▰▰▰▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"100 percent used\",\n\t\t\tPercent:       Percentage(100),\n\t\t\tExpectedGauge: \"▰▰▰▰▰\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"50 percent used\",\n\t\t\tPercent:       Percentage(50),\n\t\t\tExpectedGauge: \"▰▰▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Negative percent clamps to 0\",\n\t\t\tPercent:       Percentage(-10),\n\t\t\tExpectedGauge: \"▱▱▱▱▱\",\n\t\t},\n\t\t{\n\t\t\tCase:          \"Over 100 percent clamps to 100\",\n\t\t\tPercent:       Percentage(120),\n\t\t\tExpectedGauge: \"▰▰▰▰▰\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tresult := tc.Percent.GaugeUsed()\n\t\t\tassert.Equal(t, tc.ExpectedGauge, result, tc.Case)\n\t\t})\n\t}\n}\n\nfunc TestPercentageString(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tExpected string\n\t\tPercent  Percentage\n\t}{\n\t\t{\n\t\t\tCase:     \"Zero percent\",\n\t\t\tPercent:  Percentage(0),\n\t\t\tExpected: \"0\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"50 percent\",\n\t\t\tPercent:  Percentage(50),\n\t\t\tExpected: \"50\",\n\t\t},\n\t\t{\n\t\t\tCase:     \"100 percent\",\n\t\t\tPercent:  Percentage(100),\n\t\t\tExpected: \"100\",\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tresult := tc.Percent.String()\n\t\t\tassert.Equal(t, tc.Expected, result, tc.Case)\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "src/winres/winres.json",
    "content": "{\n  \"RT_GROUP_ICON\": {\n    \"APP\": {\n      \"0000\": [\n        \"icon.png\",\n        \"icon64.png\",\n        \"icon48.png\",\n        \"icon32.png\",\n        \"icon16.png\"\n      ]\n    }\n  },\n  \"RT_MANIFEST\": {\n    \"#1\": {\n      \"0409\": {\n        \"description\": \"A prompt theme engine for any shell.\",\n        \"minimum-os\": \"win8\",\n        \"execution-level\": \"as invoker\",\n        \"long-path-aware\": true,\n        \"segment-heap\": true\n      }\n    }\n  },\n  \"RT_VERSION\": {\n    \"#1\": {\n      \"0000\": {\n        \"fixed\": {\n          \"file_version\": \"0.0.0.0\",\n          \"product_version\": \"0.0.0.0\"\n        },\n        \"info\": {\n          \"0409\": {\n            \"CompanyName\": \"github.com/jandedobbeleer\",\n            \"FileDescription\": \"A prompt theme engine for any shell.\",\n            \"InternalName\": \"oh-my-posh\",\n            \"LegalCopyright\": \"© Jan De Dobbeleer. Licensed under MIT.\",\n            \"OriginalFilename\": \"oh-my-posh.exe\",\n            \"ProductName\": \"Oh My Posh\"\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "themes/1_shell.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffbebc\",\n          \"leading_diamond\": \"<#ff70a6> \\ue200 </>\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} <#ffffff>on</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#bc93ff\",\n          \"options\": {\n            \"time_format\": \"Monday <#ffffff>at</> 3:04 PM\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"#ee79d1\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#a9ffb4\",\n          \"style\": \"plain\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#a9ffb4\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}s <#ffffff>\\ue601</>\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"options\": {\n            \"root_icon\": \"\\uf292 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#94ffa2\",\n          \"style\": \"diamond\",\n          \"template\": \" <#ffffff>MEM:</> {{ round .PhysicalPercentUsed .Precision }}% ({{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB)\",\n          \"type\": \"sysinfo\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffafd2\",\n          \"leading_diamond\": \"<#00c7fc> \\ue285 </><#ffafd2>{</>\",\n          \"options\": {\n            \"folder_icon\": \"\\uf07b\",\n            \"folder_separator_icon\": \" \\uebcb \",\n            \"home_icon\": \"home\",\n            \"style\": \"agnoster_full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"trailing_diamond\": \"<#ffafd2>}</>\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#A9FFB4\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ef5350{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue286 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"\\ue285 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/M365Princess.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n    \"white\": \"#FFFFFF\",\n    \"tan\": \"#CC3802\",\n    \"teal\": \"#047E84\",\n    \"plum\": \"#9A348E\",\n    \"blush\": \"#DA627D\",\n    \"salmon\": \"#FCA17D\",\n    \"sky\": \"#86BBD8\",\n    \"teal_blue\": \"#33658A\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"type\": \"text\",\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"foreground\": \"p:white\",\n          \"background\": \"p:tan\",\n          \"template\": \"{{ if .Env.PNPPSHOST }} \\uf8c5 {{ .Env.PNPPSHOST }} {{ end }}\"\n        },\n        {\n          \"type\": \"text\",\n          \"style\": \"powerline\",\n          \"foreground\": \"p:white\",\n          \"background\": \"p:teal\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"template\": \"{{ if .Env.PNPPSSITE }} \\uf2dd {{ .Env.PNPPSSITE }}{{ end }}\"\n        },\n        {\n          \"type\": \"text\",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"foreground\": \"p:white\",\n          \"background\": \"p:teal\",\n          \"template\": \"{{ if .Env.PNPPSSITE }}\\u00A0{{ end }}\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"p:plum\",\n          \"foreground\": \"p:white\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"p:blush\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"p:salmon\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\u279c ({{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"p:sky\",\n          \"foreground\": \"p:white\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"p:teal_blue\",\n          \"foreground\": \"p:white\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\u2665 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/agnoster.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"{{ reason .Code }}\\u274c \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#ff0000\",\n          \"style\": \"plain\",\n          \"template\": \"# \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#007ACC\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"folder_icon\": \"\\u2026\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"style\": \"agnoster_short\",\n            \"max_depth\": 3\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#007ACC\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"cherry_pick_icon\": \"\\u2713 \",\n            \"commit_icon\": \"\\u25b7 \",\n            \"fetch_status\": true,\n            \"merge_icon\": \"\\u25f4 \",\n            \"no_commits_icon\": \"[no commits]\",\n            \"rebase_icon\": \"\\u2c62 \",\n            \"tag_icon\": \"\\u25b6 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .HEAD }}{{ if and (eq .Ahead 0) (eq .Behind 0) }} \\u2261{{end}}{{ if gt .Ahead 0 }} \\u2191{{.Ahead}}{{end}}{{ if gt .Behind 0 }} \\u2193{{.Behind}}{{end}} {{ if .Working.Changed }}+{{ .Working.Added }} ~{{ .Working.Modified }} -{{ .Working.Deleted }} {{ end }}\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0b0 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/agnoster.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#ffe9aa\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ff8080\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ reason .Code }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/agnosterplus.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"type\": \"rprompt\",\n      \"segments\": [\n        {\n          \"foreground\": \"#007ACC\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ]\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/aliens.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#61AFEF\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#C678DD\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#FF6471\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"python\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/amro.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#45F1C2\",\n          \"style\": \"plain\",\n          \"template\": \"\\ueb99 {{ .UserName }} on\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#0CA0D8\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\uf07b {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#14A5AE\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#cd5e42\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue3bf \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#CD4277\",\n          \"style\": \"plain\",\n          \"template\": \"# \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/atomic.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf120 {{ .Name }} \",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#ef5350\",\n          \"foreground\": \"#FFFB38\",\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\uf292 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#FF9248\",\n          \"foreground\": \"#2d3436\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \" \\uf07b \",\n            \"home_icon\": \"\\ue617\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf07b\\uea9c {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#FFFB38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb95{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#c5e478{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#C792EA{{ end }}\",\n            \"{{ if gt .Behind 0 }}#C792EA{{ end }}\"\n          ],\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#ef5350> \\uf046 {{ .Staging.String }}</>{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#303030\",\n          \"foreground\": \"#3C873A\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \" <#cc3a3a>\\ue5fa</> \",\n            \"yarn_icon\": \" <#348cba>\\ue6a7</>\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#306998\",\n          \"foreground\": \"#FFE873\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#0e8ac8\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"java\"\n        },\n        {\n          \"background\": \"#0e0e0e\",\n          \"foreground\": \"#0d6da8\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue77f {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#06aad5\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#f3f0ec\",\n          \"foreground\": \"#925837\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue7a8 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"rust\"\n        },\n        {\n          \"background\": \"#e1e8e9\",\n          \"foreground\": \"#055b9c\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue798 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"dart\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#ce092f\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue753 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"angular\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#de1f84\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\u03b1 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"aurelia\"\n        },\n        {\n          \"background\": \"#1e293b\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if .Error }}{{ .Error }}{{ else }}Nx {{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"nx\"\n        },\n        {\n          \"background\": \"#945bb3\",\n          \"foreground\": \"#359a25\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"<#ca3c34>\\ue624</> {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#9c1006\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#5398c2\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf104<#f5bf45>\\uf0e7</>\\uf105 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background\": \"#565656\",\n          \"foreground\": \"#faa029\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue7ad {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#316ce4\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf308 {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"#b2bec3\",\n          \"foreground\": \"#222222\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"trailing_diamond\": \"<transparent,background>\\ue0b2</>\",\n          \"options\": {\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#b8e994{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#fff34e{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#33DD2D{{end}}\"\n          ],\n          \"foreground\": \"#262626\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\uf240 \",\n            \"charging_icon\": \"\\uf1e6 \",\n            \"discharging_icon\": \"\\ue234 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#40c4ff\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"_2,15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf073 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#21c7c7\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#e0f8ff\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ef5350{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\ue285\\ueab6 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/atomicBit.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"style\": \"plain\",\n          \"template\": \"\\u256d\\u2500[<#ffff55>{{ .UserName }}</><#ff5555>@</><#55ff55>{{ .HostName }}</>]\\u2500\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#ff5555\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>[</>{{ .Path }}<#ffffff>]</>\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#FF9248\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>\\u2500(</>#<#ffffff>)</>\",\n          \"type\": \"root\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#3C873A\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \" <#cc3a3a>\\ue5fa</> \",\n            \"yarn_icon\": \" <#348cba>\\ue6a7</>\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}<#ffffff>)</>\",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#FFE873\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#ec2729\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"java\"\n        },\n        {\n          \"foreground\": \"#0d6da8\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"foreground\": \"#06aad5\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"go\"\n        },\n        {\n          \"foreground\": \"#925837\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"rust\"\n        },\n        {\n          \"foreground\": \"#055b9c\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"dart\"\n        },\n        {\n          \"foreground\": \"#ce092f\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"angular\"\n        },\n        {\n          \"foreground\": \"#de1f84\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"aurelia\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#1e293b>(</>{{ if .Error }}{{ .Error }}{{ else }}Nx {{ .Full }}{{ end }}<#1e293b>)</>\",\n          \"type\": \"nx\"\n        },\n        {\n          \"foreground\": \"#359a25\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"julia\"\n        },\n        {\n          \"foreground\": \"#9c1006\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"foreground\": \"#5398c2\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}<#ffffff>)</>\",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"foreground\": \"#faa029\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{.Profile}}{{if .Region}}@{{.Region}}{{end}}<#ffffff>)</>\",\n          \"type\": \"aws\"\n        },\n        {\n          \"foreground\": \"#316ce4\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}<#ffffff>)</>\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"linux\": \"<#ffffff>\\ue27f</>\",\n            \"macos\": \"<#ffffff>\\ue27f</>\",\n            \"windows\": \"<#ffffff>\\ue27f</>\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>(</>{{ if .WSL }}WSL at {{ end }}{{.Icon}}<#ffffff>)\\u2500</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#FFFB38{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#33DD2D{{end}}\"\n          ],\n          \"options\": {\n            \"charged_icon\": \"\\uf240 \",\n            \"charging_icon\": \"\\uf1e6 \",\n            \"discharging_icon\": \"\\ue234 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>[</>{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}%<#ffffff>]\\u2500</>\",\n          \"type\": \"battery\"\n        },\n        {\n          \"foreground\": \"#55ffff\",\n          \"options\": {\n            \"time_format\": \"_2,15:04\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>[</>\\uf073{{ .CurrentDate | date .Format }}<#ffffff>]</>\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#e0f8ff\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>[</>{{ .HEAD }}{{ if .Staging.Changed }}<#00AA00> \\u25cf {{ .Staging.String }}</>{{ end }}{{ if .Working.Changed }}<#D75F00> \\u25cf {{ .Working.String }}</>{{ end }}<#ffffff>]-</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#ecf7fa\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ef5350{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\ue285\\ueb9e \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/avit.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#C2C206\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#B5B50D\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#C94A16\",\n          \"style\": \"plain\",\n          \"template\": \"x{{ reason .Code }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue602\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/blue-owl.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#a313a8\",\n          \"foreground\": \"#FFEB3B\",\n          \"style\": \"plain\",\n          \"template\": \"\\u26a1 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#01579B\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,#01579B>\\ue0b0</>\",\n          \"options\": {\n            \"folder_icon\": \"...\",\n            \"folder_separator_icon\": \"<transparent> \\ue0bd </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#00C853\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#49404f\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,#49404f>\\ue0b0</>\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}s \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#910000\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"<transparent> \\uf12a</> {{ reason .Code }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \"\\ue0c5\",\n          \"trailing_diamond\": \"\\ue0bc\",\n          \"style\": \"diamond\",\n          \"template\": \"  {{ .UserName }}<transparent> / </>{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#3EC669\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"leading_diamond\": \"\\ue0ba\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.Folder | replace \\\"~\\\" \\\"🏚\\\" }} @ {{.HostName}}\",\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/blueish.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#26C6DA\",\n          \"leading_diamond\": \"\\ue0c5\",\n          \"options\": {\n            \"macos\": \"mac\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \\ue0b1\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#26C6DA\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#a2beef\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#00D100{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#FFCD58{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#0476d0{{end}}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \\ueb2d \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#14c2dd\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#a2c4e0\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf308 {{.Context}} :: {{if .Namespace}}{{.Namespace}}{{else}}default{{end}} \",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"#007800\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uea6c \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/bubbles.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#3EC669\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue5ff {{ .Path }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .HEAD }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E4F34A\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#7FD5EA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#42E66C\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"java\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#9B6BDF\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue624{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#9B6BDF\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"charged_icon\": \" \",\n            \"charging_icon\": \"\\u21e1 \",\n            \"discharging_icon\": \"\\u21e3 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"battery\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#AEA4BF\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 150\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .FormattedMs }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#7FD5EA\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\u276f\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/bubblesextra.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#3EC669\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue5ff {{ .Path }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#43CCEA\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E4F34A\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#7FD5EA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#42E66C\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"java\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#9B6BDF\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue624{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"julia\"\n        },\n        {\n          \"type\": \"php\",\n          \"style\": \"diamond\",\n          \"foreground\": \"#ffffff\",\n          \"background\": \"#4063D8\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"template\": \"\\ue73d {{ .Full }} \",\n          \"trailing_diamond\": \"\\ue0b4\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#9B6BDF\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"charged_icon\": \" \",\n            \"charging_icon\": \"\\u21e1 \",\n            \"discharging_icon\": \"\\u21e3 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"battery\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#AEA4BF\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 150\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .FormattedMs }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \\u276f\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/bubblesline.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#3EC669\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue5ff {{ .Path }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .HEAD }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#E4F34A\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#7FD5EA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#42E66C\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"java\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#9B6BDF\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue624{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#9B6BDF\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"charged_icon\": \"\\u25cf \",\n            \"charging_icon\": \"\\u21e1 \",\n            \"discharging_icon\": \"\\u21e3 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"battery\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#424242\",\n          \"foreground\": \"#9B6BDF\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \\u276f\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"session\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/capr4n.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue641 {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#61AFEF\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"diamond\",\n          \"template\": \"{{if .Root}} \\uf0e7 {{.UserName}} {{else}} {{.UserName}} {{end}}\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#C678DD\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"max_depth\": 2,\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.UserName}} \\u2794 📁{{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/catppuccin.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n        \"os\": \"#ACB0BE\",\n        \"pink\": \"#F5BDE6\",\n        \"lavender\": \"#B7BDF8\",\n        \"blue\":  \"#8AADF4\",\n        \"wight\": \"#FFFFFF\",\n        \"text\": \"#494D64\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"p:blue\",\n          \"foreground\": \"p:wight\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"p:blue\",\n          \"foreground\": \"p:text\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"p:pink\",\n          \"foreground\": \"p:text\",\n          \"options\": {\n            \"folder_icon\": \"..\\ue5fe..\",\n            \"home_icon\": \"~\",\n            \"style\": \"agnoster_short\"\n          },\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"p:lavender\",\n          \"foreground\": \"p:text\",\n          \"style\": \"powerline\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" {{ .HEAD }}\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/catppuccin_frappe.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n        \"os\": \"#ACB0BE\",\n        \"closer\": \"p:os\",\n        \"pink\": \"#F4B8E4\",\n        \"lavender\": \"#BABBF1\",\n        \"blue\":  \"#8CAAEE\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"p:os\",\n          \"style\": \"plain\",\n          \"template\": \"{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"p:blue\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"p:pink\",\n          \"options\": {\n            \"folder_icon\": \"..\\ue5fe..\",\n            \"home_icon\": \"~\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"p:lavender\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"template\": \"{{ .HEAD }} \",\n          \"style\": \"plain\",\n          \"type\": \"git\"\n        },\n        {\n          \"style\": \"plain\",\n          \"foreground\": \"p:closer\",\n          \"template\": \"\\uf105\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n\n"
  },
  {
    "path": "themes/catppuccin_latte.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n        \"os\": \"#ACB0BE\",\n        \"closer\": \"p:os\",\n        \"pink\": \"#ea76cb\",\n        \"lavender\": \"#7287FD\",\n        \"blue\":  \"#1e66f5\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"p:os\",\n          \"style\": \"plain\",\n          \"template\": \"{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"p:blue\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"p:pink\",\n          \"options\": {\n            \"folder_icon\": \"..\\ue5fe..\",\n            \"home_icon\": \"~\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"p:lavender\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"template\": \"{{ .HEAD }} \",\n          \"style\": \"plain\",\n          \"type\": \"git\"\n        },\n        {\n          \"style\": \"plain\",\n          \"foreground\": \"p:closer\",\n          \"template\": \"\\uf105\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n\n"
  },
  {
    "path": "themes/catppuccin_macchiato.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n        \"os\": \"#ACB0BE\",\n        \"closer\": \"p:os\",\n        \"pink\": \"#F5BDE6\",\n        \"lavender\": \"#B7BDF8\",\n        \"blue\":  \"#8AADF4\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"p:os\",\n          \"style\": \"plain\",\n          \"template\": \"{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"p:blue\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"p:pink\",\n          \"options\": {\n            \"folder_icon\": \"..\\ue5fe..\",\n            \"home_icon\": \"~\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"p:lavender\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"template\": \"{{ .HEAD }} \",\n          \"style\": \"plain\",\n          \"type\": \"git\"\n        },\n        {\n          \"style\": \"plain\",\n          \"foreground\": \"p:closer\",\n          \"template\": \"\\uf105\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/catppuccin_mocha.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n        \"os\": \"#ACB0BE\",\n        \"closer\": \"p:os\",\n        \"pink\": \"#F5C2E7\",\n        \"lavender\": \"#B4BEFE\",\n        \"blue\":  \"#89B4FA\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"p:os\",\n          \"style\": \"plain\",\n          \"template\": \"{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"p:blue\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"p:pink\",\n          \"options\": {\n            \"folder_icon\": \"..\\ue5fe..\",\n            \"home_icon\": \"~\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"p:lavender\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"template\": \"{{ .HEAD }} \",\n          \"style\": \"plain\",\n          \"type\": \"git\"\n        },\n        {\n          \"style\": \"plain\",\n          \"foreground\": \"p:closer\",\n          \"template\": \"\\uf105\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/cert.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#E36464\",\n          \"foreground\": \"#fff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"green\",\n          \"foreground\": \"#fff\",\n          \"leading_diamond\": \"\\ue0c7\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"lightCyan\",\n          \"foreground\": \"#fff\",\n          \"leading_diamond\": \"\\ue0c7\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" git({{ .HEAD }}) \",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"lightMagenta\",\n          \"foreground\": \"#fff\",\n          \"leading_diamond\": \"\\ue0c7\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/chips.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background_templates\": [\n            \"{{ if not (empty .Env.OVERRIDE_FOLDER_BADGE_BG) }}{{ .Env.OVERRIDE_FOLDER_BADGE_BG }}{{ else }}p:c-badge-folder{{ end }}\"\n          ],\n          \"foreground_templates\": [\n            \"{{ if not (empty .Env.OVERRIDE_FOLDER_BADGE_FG) }}{{ .Env.OVERRIDE_FOLDER_BADGE_FG }}{{ else }}p:c-badge-text{{ end }}\"\n          ],\n          \"leading_diamond\": \"\\uE0B6\",\n          \"options\": {\n            \"style\": \"agnoster_short\",\n            \"folder_separator_icon\": \"/\",\n            \"hide_root_location\": true,\n            \"max_depth\": 2\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\uF07B {{ .Path }}\",\n          \"trailing_diamond\": \"\\uE0B4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"p:c-git-normal\",\n          \"background_templates\": [\n            \"{{ if gt .Ahead 0 }}p:c-git-ahead{{ end }}\",\n            \"{{ if gt .Behind 0 }}p:c-git-behind{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:c-git-ahead-behind{{ end }}\",\n            \"{{ if and (not .Working.Changed) (.Staging.Changed) }}p:c-git-staging{{ end }}\",\n            \"{{ if and (.Working.Changed) (.Staging.Changed) }}p:c-git-staging-working{{ end }}\",\n            \"{{ if .UpstreamGone }}p:c-git-upstream-gone{{ end }}\",\n            \"{{ if and (.Working.Changed) (not .Staging.Changed) }}p:c-git-working{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \" \\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .HEAD }} {{ .BranchStatus }}{{ if .Working.Changed }} \\uE0B1 \\uF448 ({{ .Working.String }}){{ end }}{{ if and .Working.Changed .Staging.Changed }} \\uE0B1 {{ end }}{{ if .Staging.Changed }}{{ if not .Working.Changed }} \\uf15c {{ end }}\\uf15c ({{ .Staging.String }}){{ end }}{{ if .StashCount }} \\ueb4b {{ .StashCount }} Stash{{ if gt .StashCount 1 }}es{{ end }}{{ end }}\",\n          \"options\": {\n            \"branch_icon\": \"\\uE0A0 \",\n            \"fetch_status\": true\n          },\n          \"trailing_diamond\": \"\\uE0B4\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background_templates\": [\n            \"{{ if lt .Ms 60000 }}p:c-exec-fast{{ end }}\",\n            \"{{ if lt .Ms 3600000 }}p:c-exec-normal{{ end }}\",\n            \"{{ if lt .Ms 10800000 }}p:c-exec-slow{{ end }}\",\n            \"{{ if ge .Ms 10800000 }}p:c-exec-slower{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 1\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PRIMARY_EXEC_TIME)) }}\\udb81\\udd1f {{ .FormattedMs }}.{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if lt .CumulativeTotal.Seconds 3600 }}p:c-wakatime-undertime{{ end }}\",\n            \"{{ if lt .CumulativeTotal.Seconds 10800 }}p:c-wakatime-warm-up{{ end }}\",\n            \"{{ if lt .CumulativeTotal.Seconds 25200 }}p:c-wakatime-working{{ end }}\",\n            \"{{ if lt .CumulativeTotal.Seconds 28000 }}p:c-wakatime-quota{{ end }}\",\n            \"{{ if ge .CumulativeTotal.Seconds 28800 }}p:c-wakatime-overtime{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"options\": {\n            \"url\": \"https://wakatime.com/api/v1/users/current/summaries?start=today&end=today&api_key={{ .Env.WAKATIME_API_KEY }}\",\n            \"http_timeout\": 2000\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if and (.Env.WAKATIME_API_KEY) (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_WAKATIME))) (gt .CumulativeTotal.Seconds 0) }}\\uFA19 {{ secondsRound .CumulativeTotal.Seconds }}.{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"wakatime\",\n          \"cache\": {\n            \"duration\": \"1m\",\n            \"strategy\": \"session\"\n          }\n        },\n        {\n          \"background_templates\": [\n            \"{{ if regexMatch \\\"(^(0[6-9])|(1[0-1])):\\\" (.CurrentDate | date .Format) }}p:c-date-time-morning{{ end }}\",\n            \"{{ if regexMatch (\\\"(^1[2-4]):\\\") (.CurrentDate | date .Format) }}p:c-date-time-noon{{ end }}\",\n            \"{{ if regexMatch (\\\"(^1[5-7]):\\\") (.CurrentDate | date .Format) }}p:c-date-time-afternoon{{ end }}\",\n            \"{{ if regexMatch \\\"(^(1[8-9])|(2[0-3])):\\\" (.CurrentDate | date .Format) }}p:c-date-time-evening{{ end }}\",\n            \"{{ if regexMatch \\\"^(0[0-5]):\\\" (.CurrentDate | date .Format) }}p:c-date-time-night{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"options\": {\n            \"time_format\": \"15:04 (01/02)\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_DTIME)) }}\\uf43a {{ .CurrentDate | date .Format }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"time\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if .Error }}p:c-battery-state-error{{ end }}\",\n            \"{{ if le .Percentage 15 }}p:c-battery-15-less{{ end }}\",\n            \"{{ if and (ge .Percentage 16) (le .Percentage 30) }}p:c-battery-30-less{{ end }}\",\n            \"{{ if and (ge .Percentage 31) (le .Percentage 45) }}p:c-battery-45-less{{ end }}\",\n            \"{{ if and (ge .Percentage 46) (le .Percentage 55) }}p:c-battery-55-less{{ end }}\",\n            \"{{ if and (ge .Percentage 56) (le .Percentage 70) }}p:c-battery-70-less{{ end }}\",\n            \"{{ if and (ge .Percentage 71) (le .Percentage 90) }}p:c-battery-90-less{{ end }}\",\n            \"{{ if and (ge .Percentage 91) (le .Percentage 100) }}p:c-battery-100-less{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"True\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_BATTERY)) }}{{ else }}{{ if not .Error }}{{ if eq \\\"Charging\\\" .State.String }}\\uE315 {{ else if eq \\\"Discharging\\\" .State.String }}{{ else if eq \\\"Full\\\" .State.String }}~ {{ else }}? {{ end }}{{ if le .Percentage 15 }}\\udb80\\udc7a{{ else if and (ge .Percentage 16) (le .Percentage 30) }}\\udb80\\udc7b{{ else if and (ge .Percentage 31) (le .Percentage 45) }}\\udb80\\udc7d{{ else if and (ge .Percentage 46) (le .Percentage 55)}}\\udb80\\udc7e{{ else if and (ge .Percentage 56) (le .Percentage 70) }}\\udb80\\udc7f{{ else if and (ge .Percentage 71) (le .Percentage 80) }}\\udb80\\udc82{{ else if and (ge .Percentage 81) (le .Percentage 95) }}\\udb80\\udc82{{ else }}\\udb80\\udc79{{ end }} {{ .Percentage }}%{{ else }}!{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4\",\n          \"type\": \"battery\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"template\": \"{{ if false }}{{ end }}\",\n          \"type\": \"session\",\n          \"style\": \"diamond\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if and (.Segments.Session.SSHSession) (not .Root) }}p:c-shell-state-ssh-active{{ end }}\",\n            \"{{ if and (not .Segments.Session.SSHSession) (.Root) }}p:c-shell-state-root-active{{ end }}\",\n            \"{{ if and (.Segments.Session.SSHSession) (.Root) }}p:c-shell-state-root-ssh-active{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if or (.Segments.Session.SSHSession) (.Root) }}{{ if .Segments.Session.SSHSession }}\\uE7A2 SSH{{ end }}{{ if and (.Segments.Session.SSHSession) (.Root) }} \\uE621 {{ end }}{{ if .Root }}# Root{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"text\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if empty .Full }}p:c-project-generic-error{{ else }}p:c-project-crystal{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_CRYSTAL)) }}\\uE62F {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"crystal\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if empty .Full }}p:c-project-generic-error{{ else }}p:c-project-flutter{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_FLUTTER)) }}Flutter | {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"dart\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if .Error }}p:c-project-generic-error{{ else }}p:c-project-lua{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_LUA)) }}\\uE620 {{ if or (.Error) (empty .Full) }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"lua\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if empty .Full }}p:c-project-generic-error{{ else }}p:c-project-node{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_NODE)) }}\\uE718 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"node\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if empty .Full }}p:c-project-generic-error{{ else }}p:c-project-rust{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_RUST)) }}\\uE7A8 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"rust\"\n        },\n        {\n          \"background_templates\": [\n            \"{{ if empty .Full }}p:c-project-generic-error{{ else }}p:c-project-python{{ end }}\"\n          ],\n          \"foreground\": \"p:c-badge-text\",\n          \"leading_diamond\": \"\\uE0B6\",\n          \"options\": {\n            \"display_mode\": \"context\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if or (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON))) (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON_VENV))) }}\\uE235 {{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON)) }}{{ .Full }}{{ end }}{{ if and (.Venv) (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON))) (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON_VENV))) }} \\uE621 {{ end }}{{ if and (.Venv) (eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_PROJECT_PYTHON_VENV))) }}{{ if .Env.SEGMENT_PROJECT_PYTHON_ACTIVE_VENV_STR }}{{ .Env.SEGMENT_PROJECT_PYTHON_ACTIVE_VENV_STR }}{{ else }}{{ .Venv }}{{ end }}{{ end }}{{ end }}\",\n          \"trailing_diamond\": \"\\uE0B4 \",\n          \"type\": \"python\"\n        },\n        {\n          \"style\": \"plain\",\n          \"foreground_templates\": [\n            \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.ENABLE_ARROW_DIVIDER_COLOR_EXECUTION_RETURN)) }}p:c-badge-white{{ else }}{{ if eq .Code 0 }}p:c-badge-return-success{{ else if or (eq .Code 1) (eq .Code 130) }}p:c-badge-return-fail-term{{ else }}p:c-badge-return-custom{{ end }}{{ end }}\"\n          ],\n          \"template\": \"\\u276F\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ if .Segments.Session.SSHSession }}SSH'd{{ if or .Root }} & {{ end }}{{ end }}{{ if .Root }}# (as {{ .UserName }}) | {{ end }}{{ if .WSL }}WSL | {{ end }}{{ .Folder }} ({{ .Shell }})\",\n  \"final_space\": true,\n  \"palette\": {\n    \"c-badge-folder\": \"#FFD770\",\n    \"c-badge-text\": \"#212121\",\n    \"c-badge-white\": \"#FAFAFA\",\n    \"c-badge-return-custom\": \"#E7B9FF\",\n    \"c-badge-return-fail-term\": \"#FF8A80\",\n    \"c-badge-return-success\": \"#B2FF59\",\n    \"c-battery-15-less\": \"#FF8A80\",\n    \"c-battery-30-less\": \"#FFD180\",\n    \"c-battery-45-less\": \"#FFE57F\",\n    \"c-battery-55-less\": \"#FFFF8D\",\n    \"c-battery-70-less\": \"#F4FF81\",\n    \"c-battery-90-less\": \"#B9F6CA\",\n    \"c-battery-100-less\": \"#CCFF90\",\n    \"c-battery-state-error\": \"#FF867F\",\n    \"c-date-time-morning\": \"#FFFF8D\",\n    \"c-date-time-noon\": \"#FFF64F\",\n    \"c-date-time-afternoon\": \"#FFC400\",\n    \"c-date-time-evening\": \"#C0CFFF\",\n    \"c-date-time-night\": \"#83B9FF\",\n    \"c-exec-fast\": \"#C6FF00\",\n    \"c-exec-normal\": \"#FFFF00\",\n    \"c-exec-slow\": \"#FFD180\",\n    \"c-exec-slower\": \"#FF867F\",\n    \"c-git-ahead\": \"#6EFFFF\",\n    \"c-git-behind\": \"#FFA06D\",\n    \"c-git-ahead-behind\": \"#C0CFFF\",\n    \"c-git-normal\": \"#66FFA6\",\n    \"c-git-staging\": \"#FFD740\",\n    \"c-git-staging-working\": \"#FFB2FF\",\n    \"c-git-upstream-gone\": \"#FF867F\",\n    \"c-git-working\": \"#84FFFF\",\n    \"c-project-generic-error\": \"#FF867F\",\n    \"c-project-crystal\": \"#FFFFFF\",\n    \"c-project-flutter\": \"#6DC2FF\",\n    \"c-project-lua\": \"#BBC2FF\",\n    \"c-project-node\": \"#9CFF57\",\n    \"c-project-rust\": \"#FFAB40\",\n    \"c-project-python\": \"#FFE873\",\n    \"c-secondary-ellipsis\": \"#FFFF8D\",\n    \"c-shell-state-ssh-active\": \"#BAFFFF\",\n    \"c-shell-state-root-active\": \"#9FFFE0\",\n    \"c-shell-state-root-ssh-active\": \"#FFB2FF\",\n    \"c-wakatime-undertime\": \"#A7FFEB\",\n    \"c-wakatime-warm-up\": \"#FFFFB3\",\n    \"c-wakatime-working\": \"#FFD180\",\n    \"c-wakatime-quota\": \"#FFD0B0\",\n    \"c-wakatime-overtime\": \"#FF8A80\"\n  },\n  \"transient_prompt\": {\n    \"template\": \"{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_TRANSIENT)) }}<{{ if eq .Code 0 }}p:c-badge-return-success{{ else if or (eq .Code 1) (eq .Code 130) }}p:c-badge-return-fail-term{{ else }}p:c-badge-return-custom{{ end }}>\\uE0B6</><p:c-badge-text,{{ if eq .Code 0 }}p:c-badge-return-success{{ else if or (eq .Code 1) (eq .Code 130) }}p:c-badge-return-fail-term{{ else }}p:c-badge-return-custom{{ end }}>\\udb80\\udc5e \\uE0B1 {{ if .Segments.Executiontime.Ms }}{{ if eq \\\"False\\\" (title (default \\\"False\\\" .Env.DISABLE_SEGMENT_TRANSIENT_EXEC_TIME)) }}\\udb81\\udd1f {{ .Segments.Executiontime.FormattedMs }} \\uE621 {{ end }}{{ end }}<b>{{ if eq .Code 0 }}OK{{ else if eq .Code 1 }}FAIL{{ else if eq .Code 130 }}TERM{{ else }}Code{{ end }} ({{ .Code }})</b></><{{ if eq .Code 0 }}p:c-badge-return-success{{ else if or (eq .Code 1) (eq .Code 130) }}p:c-badge-return-fail-term{{ else }}p:c-badge-return-custom{{ end }}>\\uE0B4</> {{ end }}\\u276F \"\n  },\n  \"secondary_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"p:c-secondary-ellipsis\",\n    \"template\": \" ... \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/cinnamon.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#07585c\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#3e9022\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#de076f\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#491545\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"paused_icon\": \"\\uf04c \",\n            \"playing_icon\": \"\\ue602 \",\n            \"stopped_icon\": \"\\uf04d \"\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\uf1bc {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"spotify\"\n        },\n        {\n          \"background\": \"#491515\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ueb05 \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/clean-detailed.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#FEF5ED\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"macos\": \"\\uf179 \",\n            \"ubuntu\": \"\\uf31b \",\n            \"windows\": \"\\ue62a \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"trailing_diamond\": \"<transparent,#FEF5ED>\\ue0b2</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#FEF5ED\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf489 {{ .Name }}\",\n          \"trailing_diamond\": \"<transparent,#FEF5ED>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#516BEB\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue266 MEM: {{ round .PhysicalPercentUsed .Precision }}% | {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB \\ue266 \",\n          \"trailing_diamond\": \"<transparent,#516BEB>\\ue0b2</>\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#575656\",\n          \"foreground\": \"#d6deeb\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#17D7A0\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"style\": \"plain\",\n          \"template\": \"\\u256d\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\u2665 {{ .CurrentDate | date .Format }} |\",\n          \"type\": \"time\"\n        },\n        {\n          \"style\": \"plain\",\n          \"template\": \" \\uf292 \",\n          \"type\": \"root\"\n        },\n        {\n          \"options\": {\n            \"folder_icon\": \"\\uf07b \",\n            \"folder_separator_icon\": \" \\uf061 \",\n            \"home_icon\": \"\\ueb06 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"\\ue285 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/cloud-context.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 4,\n  \"console_title_template\": \"{{ if or .Root .Segments.Git.RepoName }}[ {{ if .Root }}Admin{{ end }}{{ if and .Root .Segments.Git.RepoName }}@{{ end }}{{ if .Segments.Git.RepoName }}{{ .Segments.Git.RepoName }}{{ end }} ]{{ end }} {{ .Folder }}\",\n  \"palette\": {\n    \"background-color\": \"transparent\",\n    \"cloud-text-amazon\": \"#4285F4\",\n    \"cloud-text-azure\": \"#4285F4\",\n    \"cloud-text-gcp\": \"#4285F4\",\n    \"cloud-text-firebase\": \"#FFA000\",\n    \"error-background\": \"#dd0033\",\n    \"error-text\": \"#242424\",\n    \"git-text\": \"#238636\",\n    \"kubernetes-text\": \"#FFBB00\",\n    \"talosctl-text\": \"#FF6C00\",\n    \"symbol-color\": \"#ffffff\",\n    \"timer-text\": \"#dd0033\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": false,\n      \"segments\": [\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:timer-text\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\",\n          \"template\": \" <p:symbol-color>\\uebaa</> {{ dateInZone .Format .CurrentDate \\\"UTC\\\" }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:kubernetes-text\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \"<p:symbol-color>\\uf308</> {{.Context}}{{if .Namespace}} \\uf061 {{.Namespace}}{{end}}\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:talosctl-text\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \"<p:symbol-color>\\udb84\\udcfe</> {{.Context}}\",\n          \"type\": \"talosctl\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:cloud-text-amazon\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\uf270</> {{.Profile}}{{if .Region}} \\uf061 {{.Region}}{{end}}\",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:cloud-text-azure\",\n          \"options\": {\n            \"source\": \"cli\"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\uebd8</> {{ .Name }}\",\n          \"type\": \"az\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:cloud-text-azure\",\n          \"options\": {\n            \"source\": \"pwsh\"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\uebd8</> (PS) {{ .Name }}\",\n          \"type\": \"az\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:cloud-text-gcp\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\udb84\\uddf6</> {{ .Project }}\",\n          \"type\": \"gcp\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:cloud-text-firebase\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\udb82\\udd67</> {{ .Project }}\",\n          \"type\": \"firebase\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:git-text\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\uF408</> {{ .RepoName }}\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:timer-text\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 1\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \" <p:symbol-color>\\ueba2</> {{ .FormattedMs }}\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:symbol-color\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \"{{ if eq .Code 0 }} \\uf004 {{ end }}\",\n          \"type\": \"status\"\n        },\n        {\n          \"background\": \"p:error-background\",\n          \"foreground\": \"p:error-text\",\n          \"leading_diamond\": \" \\ue0c5\",\n          \"trailing_diamond\": \"\\ue0c4\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if ne .Code 0 }} \\uf00d {{ .Code }}{{ if (ne (reason .Code) (toString .Code)) }} - {{ reason .Code }}{{else}}{{ end }} {{ end }}\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:timer-text\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\",\n          \"template\": \" <p:symbol-color>\\uf49b</> {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:symbol-color\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \"\\ue5ff {{ path .Path .Location }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:git-text\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"template\": \"{{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"p:error-background\",\n          \"foreground\": \"p:background-color\",\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"\\ue0c7\",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"p:background-color\",\n          \"foreground\": \"p:git-text\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if .Root }}{{ else }}<p:symbol-color> > </>{{ end }}\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ]\n}\n"
  },
  {
    "path": "themes/cloud-native-azure.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#c386f1\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ff479c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf07b  {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue23a {{ if gt .Code 0 }}\\uf00d {{ reason .Code }}{{ else }}\\uf42e{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#0077c2,transparent>\\ue0b6</> \\uf489 {{ .Name }} <transparent,#0077c2>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ueb2d \",\n            \"discharging_icon\": \"\\uf244 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue641 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#ebcc34\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf308 Kubernetes {{.Context}} cluster {{if .Namespace}}- {{.Namespace}} namespace{{end}} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"#9ec3f0\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uebd8 Subscription {{ .Name }} ({{ if .EnvironmentName | contains \\\"AzureCloud\\\" }}{{ \\\"Global\\\" }}{{ else }}{{ .EnvironmentName }}{{ end }}) \",\n          \"type\": \"az\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#E06C75\",\n          \"style\": \"plain\",\n          \"template\": \" ~ \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/cobalt2.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#1478DB\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"trailing_diamond\": \"\\uE0B0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#3AD900\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFC600{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"<transparent,background>\\uE0B0</>\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/craver.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#f1184c\",\n          \"foreground\": \"#242424\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"template\": \"\\uf0e7\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#282c34\",\n          \"foreground\": \"#3A86FF\",\n          \"leading_diamond\": \" \",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#FFBB00\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#33DD2D\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"\\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#3A86FF\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .UpstreamIcon }}{{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#0184bc\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue70c {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#8800dd\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 1\n          },\n          \"style\": \"powerline\",\n          \"template\": \" <#fefefe>\\ueba2</> {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#33DD2D\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#242424\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ueb05 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#f1184c\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}(Admin) {{end}}{{.Folder}}\",\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/darkblood.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>\\u250f[</>{{ .UserName }}<#CB4B16>]</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>[</>{{ .HEAD }}<#CB4B16>]</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>[</>\\uf0e7<#CB4B16>]</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>[x</>{{ reason .Code }}<#CB4B16>]</>\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>\\u2516[</>{{ .Path }}<#CB4B16>]></>\",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/devious-diamonds.omp.yaml",
    "content": "final_space: true\nblocks:\n  - type: prompt\n    alignment: left\n    newline: true\n    segments:\n      - type: os\n        style: diamond\n        foreground: cyan\n        options:\n          alpine: \n          arch: \n          centos: \n          debian: \n          elementary: \n          fedora: \n          gentoo: \n          linux: \n          macos: \n          manjaro: \n          mint: \n          opensuse: \n          raspbian: \n          ubuntu: \n          windows: 󰍲\n        template: \" {{ if .WSL }}{{ end }}{{.Icon}}═\"\n      - type: shell\n        style: diamond\n        leading_diamond: \n        background: green\n        foreground: black\n        template: \"  {{ .Name }} \"\n      - type: session\n        style: powerline\n        powerline_symbol: \n        background: magenta\n        foreground: black\n        template: \" {{ if .SSHSession }}󰌘 {{ end }}{{ .UserName }}@{{ .HostName }} \"\n      - type: angular\n        style: powerline\n        powerline_symbol: \n        background: lightRed\n        foreground: black\n        options:\n          fetch_version: true\n        template: \" 󰚲 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: aurelia\n        style: powerline\n        powerline_symbol: \n        background: magenta\n        foreground: white\n        options:\n          fetch_version: true\n        template: \" α {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: aws\n        style: powerline\n        powerline_symbol: \n        background: yellow\n        foreground: black\n        options:\n          display_default: false\n        template: \"  {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \"\n      - type: az\n        style: powerline\n        powerline_symbol: \n        background: lightBlue\n        foreground: black\n        template: \" ﴃ Subscription {{ .Name }} ({{ if .EnvironmentName | contains \\\"AzureCloud\\\" }}{{ \\\"Global\\\" }}{{ else }}{{ .EnvironmentName }}{{ end }}) \"\n      - type: azfunc\n        style: powerline\n        powerline_symbol: \n        background: yellow\n        foreground: black\n        options:\n          display_mode: files\n          fetch_version: false\n        template: \" ﴃ {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: go\n        style: powerline\n        powerline_symbol: \n        background: lightCyan\n        foreground: black\n        options:\n          fetch_version: true\n        template: \" 󰟓 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: java\n        style: powerline\n        powerline_symbol: \n        background: lightCyan\n        foreground: black\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: julia\n        style: powerline\n        powerline_symbol: \n        background: lightCyan\n        foreground: black\n        options:\n          fetch_version: true\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: kubectl\n        style: powerline\n        powerline_symbol: \n        background: lightYellow\n        foreground: black\n        template: \" 󰠳 {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}} \"\n      - type: node\n        style: powerline\n        powerline_symbol: \n        background: lightGreen\n        foreground: black\n        options:\n          fetch_version: true\n        template: \" 󰎙 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \"\n      - type: php\n        style: powerline\n        powerline_symbol: \n        background: lightCyan\n        foreground: black\n        template: \"  {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \"\n      - type: project\n        style: powerline\n        powerline_symbol: \n        background: lightYellow\n        foreground: black\n        template: \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }} {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} \"\n      - type: python\n        style: powerline\n        powerline_symbol: \n        background: lightYellow\n        foreground: black\n        options:\n          display_mode: files\n          fetch_virtual_env: false\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: ruby\n        style: powerline\n        powerline_symbol: \n        background: red\n        foreground: black\n        options:\n          display_mode: files\n          fetch_version: true\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: rust\n        style: powerline\n        powerline_symbol: \n        background: lightRed\n        foreground: black\n        options:\n          display_mode: files\n          fetch_version: true\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: swift\n        style: powerline\n        powerline_symbol: \n        background: blue\n        foreground: black\n        options:\n          display_mode: files\n          fetch_version: true\n        template: \"  {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \"\n      - type: time\n        style: powerline\n        powerline_symbol: \n        background: yellow\n        foreground: black\n        options:\n          time_format: Mon | 15:04:05\n        template: \" {{ .CurrentDate | date .Format }} \"\n      - type: executiontime\n        style: diamond\n        trailing_diamond: \n        background: cyan\n        foreground: black\n        options:\n          style: austin\n          threshold: 0\n        template: \" {{ .FormattedMs }} \"\n  - type: prompt\n    alignment: right\n    segments:\n      - type: git\n        style: diamond\n        leading_diamond: \n        trailing_diamond: \n        background: magenta\n        foreground: black\n        options:\n          branch_icon: \" \"\n          fetch_status: true\n          fetch_upstream_icon: true\n        template: \"{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}  {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}  {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} 󰆓 {{ .StashCount }}{{ end }}\"\n  - type: prompt\n    alignment: left\n    newline: true\n    segments:\n      - type: text\n        style: plain\n        foreground: cyan\n        template: \" ╚\"\n      - type: status\n        style: diamond\n        leading_diamond: \n        background: blue\n        background_templates:\n          - \"{{ if gt .Code 0 }}red{{ end }}\"\n        foreground: black\n        options:\n          always_enabled: true\n        template: \" {{ if gt .Code 0 }}󰋔 {{ else }} {{ end }}{{ if eq ( gt .Code 0 ) .Segments.Path.Writable}} {{ end }}\"\n      - type: path\n        style: powerline\n        powerline_symbol: \n        background: blue\n        background_templates:\n          - \"{{ if not .Writable }}red{{ end }}\"\n        foreground: black\n        options:\n          style: agnoster_short\n          folder_icon: \n          folder_separator_icon: \" 󰁕 \"\n          home_icon: 󰋜\n          max_depth: 3\n        template: \"{{ if eq ( gt .Code 0 ) .Writable }} {{ end }} {{ .Path }}{{ if not .Writable  }} 󰍁 {{ end }}{{ if and .Writable .Root }} {{end}} \"\n      - type: text\n        style: diamond\n        trailing_diamond: \n        background: blue\n        background_templates:\n          - \"{{ if and .Segments.Path.Writable (not .Root) }}{{ else }}red{{ end }}\"\n        foreground: white\n        options:\n          root_icon: \n        template: \"{{ if not .Root }}\\u2800{{ end }}{{ if and .Root ( not .Segments.Path.Writable ) }} {{ end }}{{ if and .Root .Segments.Path.Writable }}  {{ end }}\"\nconsole_title_template: \"{{ .Folder }}\"\npalette:\n  black: \"#1B1A23\"\n  blue: \"#9580FF\"\n  black-background: \"#22212C\"\n  lightBlue-brightBlue: \"#AA99FF\"\n  lightCyan-brightCyan: \"#99FFEE\"\n  lightGreen-brightGreen: \"#A2FF99\"\n  lightMagenta-brightPurple: \"#FF99CC\"\n  lightRed-brightRed: \"#FFAA99\"\n  lightWhite-brightWhite: \"#FFFFFF\"\n  lightYellow-brightYellow: \"#FFFF80\"\n  selection-selectionBackground: \"#454158\"\n  comment-brightBlack: \"#7970A9\"\n  cyan: \"#80FFEA\"\n  green: \"#8AFF80\"\n  magenta-purple: \"#FF80BF\"\n  purple: \"#DE1F84\"\n  red: \"#FF9580\"\n  white: \"#FFFFFF\"\n  white-cursorColor-foreground: \"#F8F8F2\"\n  yellow: \"#FFCA80\"\nversion: 4\n"
  },
  {
    "path": "themes/di4am0nd.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#FFBD00\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}'s \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#00C6F7\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }}/ \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#F62F2E\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on</> {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#98C379\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>via</> \\ue781 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#85C980\",\n          \"style\": \"diamond\",\n          \"template\": \"RAM:{{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB \",\n          \"trailing_diamond\": \" \",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\u250b\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#FFBD00\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2b9e \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/dracula.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#6272a4\",\n          \"foreground\": \"#f8f8f2\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#bd93f9\",\n          \"foreground\": \"#f8f8f2\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#ffb86c\",\n          \"foreground\": \"#f8f8f2\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue725 ({{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#8be9fd\",\n          \"foreground\": \"#f8f8f2\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#ff79c6\",\n          \"foreground\": \"#f8f8f2\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\u2665 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#f1fa8c\",\n          \"foreground\": \"#282a36\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue7ad {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"aws\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/easy-term.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#0c7bbb\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b2\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}\\ue712 on {{ end }}{{ .Icon }}  \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#DA627D\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"diamond\",\n          \"template\": \" 🏠  \",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#8a62da\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#191f48\",\n          \"foreground\": \"#43CCEA\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#81ff91\",\n          \"style\": \"diamond\",\n          \"template\": \"<#cc7eda> \\u007C </><#7eb8da>RAM:</> {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"foreground\": \"#81ff91\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \"<#cc7eda> \\u007C </><#7eb8da>\\ue718</> {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"type\": \"node\"\n        },\n        {\n          \"type\": \"php\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#81ff91\",\n          \"template\": \"<#cc7eda> \\u007C </><#7eb8da>\\ue73d</> {{ .Full }}\"\n        },\n        {\n          \"type\": \"npm\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#81ff91\",\n          \"template\": \"<#cc7eda> \\u007C </><#7eb8da>\\ue71e </> {{ .Full }}\"\n        },\n        {\n          \"type\": \"sysinfo\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#81ff91\",\n          \"template\": \"<> </>\"\n        },\n        {\n          \"background\": \"#cecece\",\n          \"foreground\": \"#4b4b4b\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 150\n          },\n          \"style\": \"diamond\",\n          \"template\": \"⌛  {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#cecece\",\n          \"foreground\": \"#4b4b4b\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"⏰  {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#0c7bbb\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/emodipt-extend.omp.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n    \"blocks\": [\n      {\n        \"alignment\": \"left\",\n        \"newline\": true,\n        \"segments\": [\n          {\n            \"foreground\": \"#E5C07B\",\n            \"options\": {\n              \"time_format\": \"15:04\"\n            },\n            \"style\": \"plain\",\n            \"template\": \"[{{ .CurrentDate | date .Format }}]\",\n            \"type\": \"time\"\n          },\n          {\n            \"type\": \"shell\",\n            \"style\": \"plain\",\n            \"foreground\": \"#E06C75\",\n            \"options\": {\n              \"mapped_shell_names\": {\n                \"pwsh\": \"Shell\",\n                \"powershell\": \"Shell\",\n                \"cmd\": \"Cmd\",\n                \"bash\": \"Bash\"\n              }\n            },\n            \"template\": \" \\ue795 {{ .Name }}\"\n          },\n          {\n            \"foreground\": \"#F3C267\",\n            \"foreground_templates\": [\n              \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n              \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n              \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n              \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n            ],\n            \"options\": {\n              \"branch_template\": \"{{ trunc 25 .Branch }}\",\n              \"fetch_status\": true,\n              \"fetch_upstream_icon\": true\n            },\n            \"style\": \"plain\",\n            \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n            \"type\": \"git\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n      {\n        \"alignment\": \"right\",\n        \"segments\": [\n          {\n            \"type\": \"status\",\n            \"style\": \"plain\",\n            \"foreground\": \"#b8ff75\",\n            \"foreground_templates\": [\n              \"{{ if gt .Code 0 }}#E06C75{{ end }}\"\n            ],\n            \"template\": \" x{{ reason .Code }}\"\n          },\n          {\n            \"foreground\": \"#b8ff75\",\n            \"foreground_templates\": [\n              \"{{ if gt .Code 0 }}#E06C75{{ end }}\"\n            ],\n            \"options\": {\n              \"style\": \"roundrock\",\n              \"always_enabled\": true\n            },\n            \"style\": \"diamond\",\n            \"template\": \" {{ .FormattedMs }} \",\n            \"type\": \"executiontime\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n      {\n        \"alignment\": \"left\",\n        \"newline\": true,\n        \"segments\": [\n          {\n            \"foreground\": \"#61AFEF\",\n            \"options\": {\n              \"style\": \"full\"\n            },\n            \"style\": \"plain\",\n            \"template\": \"\\ue5ff {{ .Path }}\",\n            \"type\": \"path\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n      {\n        \"alignment\": \"left\",\n        \"newline\": true,\n        \"segments\": [\n          {\n            \"foreground\": \"#E06C75\",\n            \"style\": \"plain\",\n            \"template\": \"\\u0021\",\n            \"type\": \"root\"\n          },\n          {\n            \"foreground\": \"#E06C75\",\n            \"style\": \"plain\",\n            \"template\": \"\\u276f\",\n            \"type\": \"text\"\n          }\n        ],\n        \"type\": \"prompt\"\n      }\n    ],\n    \"final_space\": true,\n    \"version\": 4\n  }\n"
  },
  {
    "path": "themes/emodipt.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#E5C07B\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"[{{ .CurrentDate | date .Format }}]\",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"#B5B50D\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#61AFEF\",\n          \"options\": {\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} on\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#F3C267\",\n          \"options\": {\n            \"branch_gone_icon\": \"\\u274e\",\n            \"branch_identical_icon\": \"\\uf14a\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#C94A16\",\n          \"style\": \"plain\",\n          \"template\": \"x{{ reason .Code }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#E06C75\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/fish.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" {{ reason .Code }}\",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#100e23\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#007ACC\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#007ACC\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>\\ue0b1</> {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0b0 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/free-ukraine.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#0057b7\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0c5\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue795 \",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"options\": {\n            \"home_icon\": \"\\ue617\",\n            \"style\": \"mixed\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#ffd700\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf1d3  {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0}}\\ueb4b {{ .StashCount }}{{ end }}{{ if gt .WorktreeCount 0}} \\uf1bb {{ .WorktreeCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#3379c5\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#3379c5{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#c57f33{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#79c533{{ end }}\",\n            \"{{ if gt .Behind 0 }}#c53379{{ end }}\"\n          ],\n          \"foreground\": \"#0057b7\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \"\\uf105\",\n          \"type\": \"git\"\n        },\n        {\n          \"leading_diamond\": \"<transparent,#49404f>\\ue0b0</>\",\n          \"style\": \"plain\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#ffd700\",\n          \"foreground\": \"#0057b7\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#a30000{{ end }}\"\n          ],\n          \"leading_diamond\": \"<transparent,#ffd700>\\ue0b0</>\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if gt .Code 0 }}\\uf421 \\uf119 {{ else }}\\uf469 \\u2665 {{ end }}\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0ac <#111111>\\ue0b2</>\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ueb2d \",\n            \"charging_icon\": \"\\uf492 \",\n            \"discharging_icon\": \"\\uf243 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}% <#111111>\\ue0b2</>\",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }} <#111111>\\ue0b2</>\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"_2,15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf073 {{ .CurrentDate | date .Format }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#0057b7\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0c5\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#ffd700\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#0057b7\",\n          \"foreground\": \"#FBD951\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"\\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#FBD951\",\n          \"foreground\": \"#0057b7\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }} \",\n          \"type\": \"session\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#0057b7\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf004\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#FBD951\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf004\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#0057b7\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf004\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#FBD951\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf004  Ukraine\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}Admin: {{end}} {{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/froczh.omp.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n    \"blocks\": [\n        {\n            \"alignment\": \"left\",\n            \"segments\": [\n                {\n                    \"background\": \"#40189c\",\n                    \"foreground\": \"#ffffff\",\n                    \"leading_diamond\": \"\\ue0b6\",\n                    \"style\": \"diamond\",\n                    \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n                    \"type\": \"os\"\n                },\n                {\n                    \"background\": \"#40189c\",\n                    \"foreground\": \"#ffffff\",\n                    \"style\": \"diamond\",\n                    \"template\": \"| {{ .UserName }}@{{ .HostName }} \",\n                    \"type\": \"session\",\n                    \"trailing_diamond\": \"\\ue0b0\"\n                },\n                {\n                    \"background\": \"#01579B\",\n                    \"foreground\": \"#ffffff\",\n                    \"leading_diamond\": \"<transparent,#01579B>\\ue0b0</>\",\n                    \"options\": {\n                        \"folder_icon\": \"...\",\n                        \"folder_separator_icon\": \"<transparent> \\ue0bd </>\",\n                        \"home_icon\": \"\\ueb06\",\n                        \"style\": \"agnoster_short\"\n                    },\n                    \"style\": \"diamond\",\n                    \"template\": \" {{ .Path }} \",\n                    \"trailing_diamond\": \"\\ue0b0\",\n                    \"type\": \"path\"\n                },\n                {\n                    \"background\": \"#00C853\",\n                    \"background_templates\": [\n                        \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n                        \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n                        \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n                        \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n                    ],\n                    \"foreground\": \"#000000\",\n                    \"powerline_symbol\": \"\\ue0b0\",\n                    \"options\": {\n                        \"fetch_status\": true\n                    },\n                    \"style\": \"powerline\",\n                    \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n                    \"type\": \"git\"\n                },\n                {\n                    \"type\": \"dotnet\",\n                    \"style\": \"powerline\",\n                    \"powerline_symbol\": \"\\uE0B0\",\n                    \"foreground\": \"#000000\",\n                    \"background\": \"#00ffff\",\n                    \"template\": \" \\uE77F {{ .Full }} \"\n                },\n                {\n                    \"type\": \"angular\",\n                    \"style\": \"powerline\",\n                    \"powerline_symbol\": \"\\uE0B0\",\n                    \"background\": \"#000000\",\n                    \"foreground\": \"#ffffff\",\n                    \"template\": \" \\uE753 {{ if .Error }}<#FE4A49>?</>{{ else }}{{ .Full }}{{ end }} \"\n                },\n                {\n                    \"type\": \"aurelia\",\n                    \"style\": \"powerline\",\n                    \"powerline_symbol\": \"\\uE0B0\",\n                    \"background\": \"#000000\",\n                    \"foreground\": \"#ffffff\",\n                    \"template\": \" \\uE753 {{ if .Error }}<#DE1F84>?</>{{ else }}{{ .Full }}{{ end }} \"\n                },\n                {\n                    \"type\": \"node\",\n                    \"style\": \"powerline\",\n                    \"powerline_symbol\": \"\\ue0b0\",\n                    \"background\": \"#000000\",\n                    \"foreground\": \"#45bf17\",\n                    \"template\": \" \\ue718 {{ .Full }} \"\n                },\n                {\n                    \"type\": \"npm\",\n                    \"style\": \"powerline\",\n                    \"powerline_symbol\": \"\\ue0b0\",\n                    \"background\": \"#000000\",\n                    \"foreground\": \"#FE4A49\",\n                    \"template\": \"\\ue71e {{ .Full }} \"\n                },\n                {\n                    \"background\": \"#910000\",\n                    \"foreground\": \"#ffffff\",\n                    \"powerline_symbol\": \"\\ue0b0\",\n                    \"style\": \"powerline\",\n                    \"template\": \"<transparent> \\uf12a</> {{ reason .Code }} \",\n                    \"type\": \"status\"\n                }\n            ],\n            \"type\": \"prompt\"\n        },\n        {\n            \"alignment\": \"right\",\n            \"segments\": [\n                {\n                    \"background\": \"#29315A\",\n                    \"foreground\": \"#ffffff\",\n                    \"leading_diamond\": \"\\ue0c5\",\n                    \"options\": {\n                        \"style\": \"dallas\",\n                        \"threshold\": 0\n                    },\n                    \"style\": \"diamond\",\n                    \"template\": \"\\ueba2 {{ .FormattedMs }}s \",\n                    \"type\": \"executiontime\"\n                },\n                {\n                    \"background\": \"#29315A\",\n                    \"foreground\": \"#3EC669\",\n                    \"options\": {\n                        \"time_format\": \"15:04:05 | Monday\"\n                    },\n                    \"style\": \"plain\",\n                    \"template\": \"<transparent> \\ue0ba\\ue0bc </>{{ .CurrentDate | date .Format }} \",\n                    \"type\": \"time\"\n                }\n            ],\n            \"type\": \"prompt\"\n        },\n        {\n            \"alignment\": \"left\",\n            \"newline\": true,\n            \"segments\": [\n                {\n                    \"foreground\": \"#ffffff\",\n                    \"foreground_templates\": [\n                        \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n                    ],\n                    \"options\": {\n                        \"always_enabled\": true\n                    },\n                    \"style\": \"plain\",\n                    \"template\": \"\\u276f \",\n                    \"type\": \"status\"\n                }\n            ],\n            \"type\": \"prompt\"\n        }\n    ],\n    \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.Folder | replace \\\"~\\\" \\\"🏚\\\" }} @ {{.HostName}}\",\n    \"version\": 4\n}\n"
  },
  {
    "path": "themes/glowsticks.omp.yaml",
    "content": "# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\nblocks:\n  - alignment: left\n    segments:\n      # Session\n      - background: p:black\n        foreground: p:white\n        invert_powerline: true\n        powerline_symbol: \n        style: powerline\n        template: \"{{ .UserName }}@{{ .HostName }} \"\n        type: session\n\n      # Path\n      - background: p:orange\n        foreground: p:white\n        powerline_symbol: \n        options:\n          home_icon: \"\"\n          style: folder\n        style: powerline\n        template: \"  {{ .Path }} \"\n        type: path\n\n      # Execution time\n      - background: p:darkred\n        foreground: p:white\n        powerline_symbol: \n        options:\n          always_enabled: true\n          style: round\n        style: powerline\n        template: \" 󰔟{{ .FormattedMs }} \"\n        type: executiontime\n\n      # Exit code\n      - background: p:blue\n        background_templates:\n          - \"{{ if gt .Code 0 }}p:red{{ end }}\"\n        foreground: p:white\n        powerline_symbol: \n        options:\n          always_enabled: true\n        style: diamond\n        template: \" {{ if gt .Code 0 }} {{ reason .Code }}{{ else }}{{ end }} \"\n        trailing_diamond: \n        type: status\n    type: prompt\n  - alignment: right\n    segments:\n      # Shell\n      - background: p:black\n        foreground: p:white\n        style: plain\n        template: <p:black,transparent></> {{ .Name }}<transparent,p:black></>\n        type: shell\n\n      # Battery\n      - background_templates:\n          - '{{if eq \"Charging\" .State.String }}p:green{{end}}'\n          - '{{if eq \"Discharging\" .State.String}}p:orange{{end}}'\n        foreground: p:white\n        leading_diamond: \n        options:\n          charged_icon: 󰂄\n          charging_icon: 󰂄\n          discharging_icon: \"󰁹 \"\n        style: diamond\n        template: \" {{.Templates }}{{ .Percentage}}󰏰 <transparent></>\"\n        templates:\n          - '{{if eq \"Discharging\" .State.String}}{{if lt .Percentage 11}}󰁺{{else if lt .Percentage 21}}󰁻{{else if lt .Percentage 31}}󰁼{{else if lt .Percentage 41}}󰁽{{else if lt .Percentage 51}}󰁾{{else if lt .Percentage 61}}󰁾{{else if lt .Percentage 71}}󰂀{{else if lt .Percentage 81}}󰂁{{else if lt .Percentage 91}}󰂂{{else}}󰁹{{end}}{{end}}'\n          - '{{if eq \"Charging\" .State.String}}{{ if lt .Percentage 21}}󰂆{{else if lt .Percentage 31}}󰂇{{else if lt .Percentage 41}}󰂈{{else if lt .Percentage 61}}󰂉{{else if lt .Percentage 81}}󰂊{{else if lt .Percentage 91}}󰂋{{else}}󰂄{{end}}{{end}}'\n        templates_logic: first_match\n        type: battery\n    type: rprompt\nfinal_space: true\nconsole_title_template:  {{ .Shell }} in {{ if ne .Folder \"~\"}} {{ .Folder }}{{else}}{{end}}\npalette:\n  black: \"#33395b\"\n  blue: \"#359ddd\"\n  darkred: \"#7c0a16\"\n  green: \"#277b48\"\n  orange: \"#ff972e\"\n  red: \"#de3142\"\n  white: \"#efeef4\"\nsecondary_prompt:\n  background: transparent\n  foreground: p:white\n  template: \" \"\ntransient_prompt:\n  background: transparent\n  foreground: p:white\n  template: \" \"\nversion: 4\n"
  },
  {
    "path": "themes/gmay.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#3A86FF\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#3A86FF\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ff479c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#4caf50\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"time_format\": \"2006-01-02 15:04:05\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ueb05 \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#f1184c\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf0a9 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/grandpa-style.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#dd1e1e\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#5a3d29\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"folder_icon\": \"...\",\n            \"folder_separator_icon\": \"<transparent> \\ue0bd </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#00C853\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"<parentBackground,background>\\ue0b0</>\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2ba1bb\",\n          \"foreground\": \"#5a3d29\",\n          \"leading_diamond\": \"<parentBackground,background>\\ue0b0</>\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}s \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#910000\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ if gt .Code 0 }}<parentBackground,background>\\ue0b0</><transparent> \\uf12a</> {{ reason .Code }} <background,transparent>\\ue0b0</>{{ else }}<parentBackground,transparent>\\ue0b0</>{{ end }}\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#5a3d29\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \"\\ue0c5\",\n          \"style\": \"diamond\",\n          \"template\": \"  {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}<transparent> / </>{{ .HostName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#5a3d29\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"time_format\": \"3:04:05 PM\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent> \\ue0ba\\ue0bc </>{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.Folder | replace \\\"~\\\" \\\"🏚\\\" }} @ {{.HostName}}\",\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/gruvbox.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#3A3A3A\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"powerline\",\n          \"template\": \"{{ if .WSL }}WSL at{{ end }} {{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#458588\",\n          \"foreground\": \"#282828\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#98971A\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#282828\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"branch_icon\": \"\\uE0A0 \",\n            \"branch_identical_icon\": \"\\u25CF\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#8ED1F7\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#4063D8\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#FFDE57\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#AE1401\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#FEAC19\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background_templates\": [\n            \"{{if contains \\\"default\\\" .Profile}}#FFA400{{end}}\",\n            \"{{if contains \\\"jan\\\" .Profile}}#f1184c{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_default\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0ad \",\n          \"type\": \"root\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/half-life.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7E46B6\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"in \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#87FF00\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#5FD7FF\",\n          \"options\": {\n            \"branch_ahead_icon\": \"\",\n            \"branch_behind_icon\": \"\",\n            \"branch_gone_icon\": \"\",\n            \"branch_icon\": \"\",\n            \"branch_identical_icon\": \"\",\n            \"cherry_pick_icon\": \"\",\n            \"commit_icon\": \"\",\n            \"fetch_status\": true,\n            \"merge_icon\": \"\",\n            \"rebase_icon\": \"\",\n            \"revert_icon\": \"\",\n            \"tag_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on</> {{ .HEAD }}{{ if .Staging.Changed }}<#87FF00> \\u25cf {{ .Staging.String }}</>{{ end }}{{ if .Working.Changed }}<#D75F00> \\u25cf {{ .Working.String }}</>{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#D75F00\",\n          \"style\": \"plain\",\n          \"template\": \"λ \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/honukai.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#FFFFFF\",\n          \"style\": \"plain\",\n          \"template\": \"<#0377C8># </><#0377C8>{{ .UserName }}</> <#ffffff>in</> <#4A9207>{{ .HostName }}</> \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#0973C0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#B8B80A\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on git:</>{{ .HEAD }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"[{{ .CurrentDate | date .Format }}]\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#CECE04\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#100e23\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#CB4B16\",\n          \"style\": \"plain\",\n          \"template\": \" {{ reason .Code }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#CC4B16\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/hotstick.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"yellow\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue0a2 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"lightBlue\",\n          \"foreground\": \"black\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"mixed\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"green\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}yellow{{ end }}\"\n          ],\n          \"foreground\": \"black\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_ahead_icon\": \"\\u2191\",\n            \"branch_behind_icon\": \"\\u2193\",\n            \"branch_gone_icon\": \"\\u2262\",\n            \"branch_icon\": \"\\ue0a0 \",\n            \"branch_identical_icon\": \"\\u2261\",\n            \"cherry_pick_icon\": \"\\u2713 \",\n            \"commit_icon\": \"\\u25b7 \",\n            \"fetch_status\": true,\n            \"merge_icon\": \"\\u25f4 \",\n            \"no_commits_icon\": \"[no commits]\",\n            \"rebase_icon\": \"\\u2c62 \",\n            \"tag_icon\": \"\\u25b6 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }} {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} {{ .Working.String }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/hul10.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n    \"white\": \"#f7f7f7\",\n    \"black\": \"#111111\"\n  },\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"p:white\",\n          \"style\": \"plain\",\n          \"template\": \"\\u250c\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#464646\",\n          \"foreground\": \"p:white\",\n          \"options\": {\n            \"windows\": \"\\ue62a\",\n            \"linux\": \"\\uf17c\",\n            \"ubuntu\": \"\\uf31b\",\n            \"macos\": \"\\uf179\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{.Icon}}{{if .WSL}} (WSL){{end}}\\u2800\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"p:white\",\n          \"foreground\": \"p:black\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf489 {{.Name}}\\u2800\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#ffe093\",\n          \"foreground\": \"p:black\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf2c0 {{.HostName}}\\ue0bd{{.UserName}}\\u2800\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ffffd6\",\n          \"foreground\": \"p:black\",\n          \"options\": {\n            \"branch_icon\": \" \\ue0a0 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{.HEAD}}\\u2800\",\n          \"type\": \"git\"\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#b3ffde\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 0\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{.FormattedMs}}\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#b3ffde\",\n          \"options\": {\n            \"time_format\": \"02/01/06 15:04\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<p:white> · </>{{.CurrentDate | date .Format}}\",\n          \"type\": \"time\"\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"p:white\",\n          \"options\": {\n            \"folder_icon\": \"\\uf07b\",\n            \"folder_separator_template\": \"<#93d0ff> \\u00bb </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<p:white>\\u2514</><#93d0ff>[</> {{.Path}} <#93d0ff>]</>\",\n          \"type\": \"path\"\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#81ff91\",\n          \"foreground_templates\": [\n            \"{{if gt .Code 0}}#ff3030{{end}}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f\",\n          \"type\": \"status\"\n        }\n      ]\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}[root] {{end}}{{.Shell}} in <{{.Folder}}>\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/hunk.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#c44569\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#c44569\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#f78fb3\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#f78fb3\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#caffbf\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FCA17D{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f17c37{{ end }}\"\n          ],\n          \"foreground\": \"#333333\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }} {{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#86BBD8\",\n          \"foreground\": \"#FFD700\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \" \\u26a1\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#86BBD8\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#33658A\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Name }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"shell\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#69FF94>\\u276f</>\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 5\n}"
  },
  {
    "path": "themes/huvix.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#FFE082\",\n          \"style\": \"plain\",\n          \"template\": \"@{{ .UserName }} \\u279c\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#7FD5EA\",\n          \"style\": \"powerline\",\n          \"template\": \"(\\ue626{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}) \",\n          \"type\": \"go\"\n        },\n        {\n          \"foreground\": \"#9e7eff\",\n          \"style\": \"powerline\",\n          \"template\": \"(\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}) \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#E8CC97>git(</>{{ .HEAD }}<#E8CC97>) </>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#FFAB91\",\n          \"options\": {\n            \"always_enabled\": false,\n            \"style\": \"austin\",\n            \"threshold\": 100\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .FormattedMs }}\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#193549\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#64B5F6{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#E36464{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#66BB6A{{end}}\"\n          ],\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ue234 \",\n            \"discharging_icon\": \"\\ue231 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"[{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295]\",\n          \"type\": \"battery\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/if_tea.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#1865f5\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\uf179 \",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31b \",\n            \"windows\": \"\\ue62a \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"trailing_diamond\": \"<transparent,>\\ue0b2</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#00c7fc\",\n          \"foreground\": \"#000000\",\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"<transparent,#00c7fc>\\ue0b0</>\",\n          \"template\": \" \\ue266 CPU: {{ round .PhysicalPercentUsed .Precision }}% | \",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#00c7fc\",\n          \"foreground\": \"#000000\",\n          \"style\": \"diamond\",\n          \"template\": \"RAM: {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB \\ue266 \",\n          \"trailing_diamond\": \"<transparent,#00c7fc>\\ue0b2</>\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#2343e2\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#ee79d1\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#91f2ff\",\n          \"style\": \"plain\",\n          \"template\": \"\\u256d\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#91f2ff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf489 {{ .Name }} \",\n          \"trailing_diamond\": \"<transparent,#91f2ff>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#ff8c94\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"3:04:05 PM | Monday\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue641 {{ .CurrentDate | date .Format }} \\uf073 \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        },\n        {\n          \"options\": {\n            \"root_icon\": \"\\uf292 \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#f8677b\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"<transparent,#F8677b>\\ue0b0</>\",\n          \"options\": {\n            \"folder_icon\": \"\\uf07b \",\n            \"folder_separator_icon\": \" \\uf061 \",\n            \"home_icon\": \"\\uf46d\",\n            \"style\": \"agnoster_full\"\n          },\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#00BCF9\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ef5350{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\\ue285  \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title\": true,\n  \"console_title_style\": \"template\",\n\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"\\ue285 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/illusi0n.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"segments\": [\n        {\n          \"foreground\": \"#ff8800\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ round .PhysicalPercentUsed .Precision }}% \",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"foreground\": \"#ff8800\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB \",\n          \"type\": \"sysinfo\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ff8800\",\n          \"options\": {\n            \"macos\": \"mac\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"#ff8800\",\n          \"style\": \"plain\",\n          \"template\": \"$\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#ff8800\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}:\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#62c0ff\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#62c0ff\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#6287ff{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#7f62ff{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#9962ff{{ end }}\",\n            \"{{ if gt .Behind 0 }}#c062ff{{ end }}\"\n          ],\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ff8800>on</> {{.UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#ff8800\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/iterm2.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#fff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"windows\": \"\\uf179\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#d2ff5e\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#0087D8\",\n          \"foreground\": \"#003544\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#d2ff5e\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f17c37{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#33DD2D\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#242424\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea6c \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#33DD2D{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#FFCD58{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#0476d0{{end}}\"\n          ],\n          \"foreground\": \"#242424\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \\ueb2d \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#0087D8\",\n          \"foreground\": \"#003544\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"display_mode\": \"context\",\n            \"fetch_virtual_env\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ .Venv }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#fff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \"<#fff> \\ue641 </>{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#FFD700\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#f1184c\",\n          \"style\": \"plain\",\n          \"template\": \"🚀 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FFD700\",\n    \"template\": \"{{if .Root}}\\u26a1 {{end}}🚀 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/jandedobbeleer.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#c386f1\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ff479c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"~\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea83  {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#8ED1F7\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#4063D8\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#FFDE57\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#AE1401\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#FEAC19\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background_templates\": [\n            \"{{if contains \\\"default\\\" .Profile}}#FFA400{{end}}\",\n            \"{{if contains \\\"jan\\\" .Profile}}#f1184c{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_default\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#111111\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0ad \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> \\ueba2 {{ .FormattedMs }}\\u2800\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#00897b\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#e91e63{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\ue23a \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"segments\": [\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#0077c2,transparent>\\ue0b6</> \\uf489 {{ .Name }} <transparent,#0077c2>\\ue0b2</>\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#1BD760\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"paused_icon\": \"\\uf04c \",\n            \"playing_icon\": \"\\uf04b \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf167 {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"ytm\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ue234 \",\n            \"discharging_icon\": \"\\ue231 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/jblab_2021.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#0C212F\",\n          \"foreground\": \"#FFFFFF\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Icon }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#DE2121\",\n          \"foreground\": \"#FFFFFF\",\n          \"leading_diamond\": \"<transparent,#DE2121>\\ue0b0</>\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7 \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#26BDBB\",\n          \"foreground\": \"#0C212F\",\n          \"leading_diamond\": \"<transparent,#26BDBB>\\ue0b0</>\",\n          \"options\": {\n            \"folder_icon\": \"...\",\n            \"folder_separator_icon\": \"<transparent> \\ue0b1 </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#280C2E\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#7621DE{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#7621DE{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#7621DE{{ end }}\",\n            \"{{ if gt .Behind 0 }}#7621DE{{ end }}\"\n          ],\n          \"foreground\": \"#FFFFFF\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#0C212F\",\n          \"foreground\": \"#FFFFFF\",\n          \"leading_diamond\": \"<transparent,#0C212F>\\ue0b0</>\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#26BDBB\",\n          \"foreground\": \"#0C212F\",\n          \"leading_diamond\": \"<transparent,#26BDBB>\\ue0b0</>\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}s \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#910000\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"style\": \"diamond\",\n          \"template\": \"<transparent> \\uf12a</> {{ reason .Code }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.Folder | replace \\\"~\\\" \\\"🏠\\\"}} @ {{.HostName}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/jonnychipz.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#4707a8\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0c2\\ue0c2\",\n          \"style\": \"diamond\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#4707a8\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#1a1af5\",\n          \"foreground\": \"#ffffff\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uebd8 {{ .Name }} \",\n          \"type\": \"az\"\n        },\n        {\n          \"background\": \"#4707a8\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue23a \",\n          \"leading_diamond\": \"<transparent>\\ue0b0</>\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0c2\\ue0c2\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}\\ue712 on {{ end }}{{ .Icon }}<#000000> \\ue0b1</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7<#ffffff> \\ue0b1</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"options\": {\n            \"folder_icon\": \"<#000000>\\ue5fe </>\",\n            \"folder_separator_icon\": \"<#000000>\\ue0b1 </>\",\n            \"home_icon\": \"\\ueb06 \",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000> \\ue5ff </>{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffea00{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#2EC4B6{{ end }}\",\n            \"{{ if gt .Behind 0 }}#8A4FFF{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .UpstreamIcon }}{{ .HEAD }}{{ if .Staging.Changed }}<#2FDA4E> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }}<#E84855> \\uf044 {{ .Working.String }}</>{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .WorkspaceName }} \",\n          \"type\": \"terraform\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#1a1af5\",\n          \"style\": \"plain\",\n          \"template\": \" \\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}root :: {{end}}{{.Shell}} :: {{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/json.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#F1FA8C\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#42E66C>\\ueaf7 </><b>{{ .Path }}</b>\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#ffffff> \\u26A1 </><b>{{ .HEAD }}</b>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#ff0000\",\n          \"style\": \"diamond\",\n          \"template\": \"<#ff0000> \\u25C9</>\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#FFFFFF\",\n          \"style\": \"plain\",\n          \"template\": \">\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/jtracey93.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#EB9654\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"lightYellow\",\n          \"foreground\": \"#3f3f3f\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#25AFF3\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" branch ({{ .HEAD }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#1BD760\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"paused_icon\": \"\",\n            \"playing_icon\": \"\",\n            \"stopped_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"spotify\"\n        },\n        {\n          \"background\": \"#cc00ff\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#49404f\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }}s \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"type\": \"status\",\n          \"style\": \"diamond\",\n          \"foreground\": \"#ffffff\",\n          \"background\": \"#00897b\",\n          \"background_templates\": [\n            \"{{ if .Error }}#e91e63{{ end }}\"\n          ],\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          }\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"type\": \"prompt\",\n      \"newline\": true,\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ]\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/jv_sitecorian.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#185F7B\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0c5\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#185F7B\",\n          \"foreground\": \"#185F7B\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#185F7B\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"home_icon\": \"\\ue617  \",\n            \"style\": \"mixed\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#6f42c1\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"leading_diamond\": \"<transparent,#49404f>\\ue0b0</>\",\n          \"style\": \"plain\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#4caf50\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}red{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if gt .Code 0 }}\\uf421{{ else }}\\uf469 \\u2665{{ end }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#2B2B2B\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0c5\",\n          \"options\": {\n            \"time_format\": \"3:04:05 PM\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }}<#ffffff> \\ue641 </>\",\n          \"trailing_diamond\": \"\\ue0c4\",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#2B2B2B\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0c5\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}<#ffffff> \\uf252 </>\",\n          \"trailing_diamond\": \"\\ue0c4\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#2B2B2B\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0c5\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#2B2B2B\",\n          \"foreground\": \"#1CA6A3\",\n          \"powerline_symbol\": \"\\ue0c4\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#2B2B2B\",\n          \"foreground\": \"#FBD951\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"\\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#DC291E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }} \",\n          \"type\": \"session\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#666666\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf489 {{ .Name }}\",\n          \"type\": \"shell\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}Admin: {{end}} {{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/kali.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"lightBlue\",\n          \"foreground_templates\": [\n            \"{{ if .Root }}lightRed{{ end }}\"\n          ],\n          \"style\": \"plain\",\n          \"template\": \"<{{ if .Root }}lightBlue{{ else }}green{{ end }}>\\u250c\\u2500\\u2500(</>{{ .UserName }}{{ if .Root }}💀{{ else }}㉿{{ end }}{{ .HostName }}<{{ if .Root }}lightBlue{{ else }}green{{ end }}>)</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"yellow\",\n          \"options\": {\n            \"fetch_version\": false,\n            \"fetch_virtual_env\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<{{ if .Root }}lightBlue{{ else }}green{{ end }}>-[</>\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }}{{ end }}{{ .Full }}{{ end }}<{{ if .Root }}lightBlue{{ else }}green{{ end }}>]</>\",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"lightWhite\",\n          \"options\": {\n            \"folder_separator_icon\": \"<#c0c0c0>/</>\",\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<{{ if .Root }}lightBlue{{ else }}green{{ end }}>-[</>{{ .Path }}<{{ if .Root }}lightBlue{{ else }}green{{ end }}>]</>\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"white\",\n          \"style\": \"plain\",\n          \"template\": \"<{{ if .Root }}lightBlue{{ else }}green{{ end }}>-[</>{{ .HEAD }}<{{ if .Root }}lightBlue{{ else }}green{{ end }}>]</>\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"white\",\n          \"options\": {\n            \"always_enabled\": true,\n            \"style\": \"round\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"foreground\": \"green\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}red{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if gt .Code 0 }}\\uea76{{else}}\\uf42e{{ end }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightBlue\",\n          \"style\": \"plain\",\n          \"template\": \"<{{ if .Root }}lightBlue{{ else }}green{{ end }}>\\u2514\\u2500</>{{ if .Root }}<lightRed>#</>{{ else }}${{ end }} \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/kushal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"console_title_template\": \"{{ if .Root }}root @ {{ end }}{{ .Shell }} in {{ .Folder }}\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#575656\",\n          \"foreground\": \"#D6DEEB\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}\\ue712 on {{ end }}{{ .Icon }} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#00C7FC\",\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf489 {{ .Name }} \",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#EF541C\",\n          \"foreground\": \"#D6DEEB\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf09c admin \",\n          \"type\": \"root\"\n        },\n        {\n          \"type\": \"cmake\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"foreground\": \"#E8EAEE\",\n          \"background\": \"#1E9748\",\n          \"template\": \" \\ue61e \\ue61d cmake {{ .Full }} \"\n        },\n        {\n          \"type\": \"python\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"display_mode\": \"context\"\n          },\n          \"foreground\": \"#011627\",\n          \"background\": \"#FFDE57\",\n          \"template\": \" \\ue73c {{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }} \"\n        },\n        {\n          \"type\": \"go\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"foreground\": \"#ffffff\",\n          \"background\": \"#7FD5EA\",\n          \"template\": \" \\u202d\\ue626 {{ .Full }} \"\n        },\n        {\n          \"type\": \"rust\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"foreground\": \"#193549\",\n          \"background\": \"#99908A\",\n          \"template\": \" \\ue7a8 {{ .Full }} \"\n        },\n        {\n          \"background\": \"#1BD4CD\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#16B1AC{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#16B1AC{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B787D7{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B787D7{{ end }}\"\n          ],\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#CAEBE1> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#03DED3\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#E44141{{ end }}\"\n          ],\n          \"foreground\": \"#414141\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#D6DEEB{{ end }}\"\n          ],\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"background\": \"#575656\",\n          \"foreground\": \"#D6DEEB\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf252 {{ .FormattedMs }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#D6DEEB\",\n          \"style\": \"plain\",\n          \"template\": \"\\u256d\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#F2D3B6\",\n          \"options\": {\n            \"time_format\": \"<#D6DEEB>\\ue641 15:04:05</> <#79DFE1>|</> \\uf073 2 Jan, Monday\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .CurrentDate | date .Format }} <#79DFE1>|</>\",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"#B6D6F2\",\n          \"leading_diamond\": \"<#00C7FC> \\uf07b </><#B6D6F2> in </>\",\n          \"options\": {\n            \"folder_icon\": \" \\uf07c \",\n            \"folder_separator_icon\": \" \\uf061 \",\n            \"home_icon\": \"\\ueb06 \",\n            \"style\": \"agnoster_short\",\n            \"max_depth\": 3\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#D6DEEB\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#D6DEEB\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"osc99\": true,\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"\\ue285 \"\n  },\n  \"secondary_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#D6DEEB\",\n    \"template\": \"\\u2570\\u2500\\u276f \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/lambda.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#F5F5F5\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue7ad \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#B80101\",\n          \"options\": {\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#B80101\",\n          \"style\": \"plain\",\n          \"template\": \" <#F5F5F5>git:</>{{ .HEAD }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/lambdageneration.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#fb7e14\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \\ue0b1\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#fb7e14\",\n          \"options\": {\n            \"always_enabled\": true,\n            \"style\": \"austin\",\n            \"threshold\": 500\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .FormattedMs }} \\ue0b1\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#fb7e14\",\n          \"trailing_diamond\": \"\\ue0c6\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#D4E157\",\n          \"style\": \"plain\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#26C6DA\",\n          \"foreground_templates\": [\n            \"{{ if eq \\\"Full\\\" .State.String }}#292929{{ end }}\",\n            \"{{ if eq \\\"Charging\\\" .State.String }}#40c4ff{{ end }}\",\n            \"{{ if eq \\\"Discharging\\\" .State.String }}#fb7e14{{ end }}\"\n          ],\n          \"options\": {\n            \"charged_icon\": \"\\uf240 \",\n            \"charging_icon\": \"\\ueb2d \",\n            \"discharging_icon\": \"\\ueb2d \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }} \\ue0b1\",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#292929{{ end }}\"\n          ],\n          \"foreground\": \"#fb7e14\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if gt .Code 0 }}\\uf00d {{ reason .Code }}{{ else }}\\uf00c{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#fb7e14\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }} <#fb7e14>\\ue0b3</> \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#292929\",\n          \"foreground\": \"#fb7e14\",\n          \"options\": {\n            \"time_format\": \"15:04:05, _2\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"{{ .CurrentDate | date .Format }} \\uf073 \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#fb7e14\",\n          \"foreground\": \"#292929\",\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"\\u2570\\u2500\\ue0b6\",\n          \"template\": \"\\ue7ad\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/larserikfinholt.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#c386f1\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ff479c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"home_icon\": \"~\",\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea83  {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> \\ueba2{{ .FormattedMs }}\\u2800\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"background_templates\": [\n            \"{{ if gt .Hours 100 }}#dc3545{{ end }}\",\n            \"{{ if and (lt .Hours 100) (gt .Hours 50) }}#ffc107{{ end }}\",\n            \"{{ if lt .Hours 50 }}#28a745{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"foreground_templates\": [\n            \"{{ if gt .Hours 100 }}#FFFFFF{{ end }}\",\n            \"{{ if and (lt .Hours 100) (gt .Hours 50) }}#343a40{{ end }}\",\n            \"{{ if lt .Hours 50 }}#FFFFFF{{ end }}\"\n          ],\n          \"options\": {\n            \"access_token\": \"0ccbd2ac1e37a5b84101468df3d367177fe02ab3\",\n            \"http_timeout\": 1500,\n            \"refresh_token\": \"111111111111111111111111111111\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{.Name}} {{.Ago}} {{.Icon}} \",\n          \"type\": \"strava\"\n        },\n        {\n          \"background\": \"#00897b\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#e91e63{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\ue23a \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/lightgreen.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#dd1e1e\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#3EC669\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue5ff {{ .Path }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#00ff0d\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#306998\",\n          \"foreground\": \"#FFE873\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#06aad5\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#565656\",\n          \"foreground\": \"#faa029\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue7ad {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"aws\"\n        },\n        {\n          \"type\": \"terraform\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\uE0B0\",\n          \"foreground\": \"#000000\",\n          \"background\": \"#ebcc34\",\n          \"template\": \"{{.WorkspaceName}}\"\n        },\n        {\n          \"background\": \"#316ce4\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf308 {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"kubectl\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"options\": {\n              \"style\": \"roundrock\",\n              \"always_enabled\": true\n            },\n            \"style\": \"diamond\",\n            \"template\": \"{{ .FormattedMs }} \",\n            \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#3c3c3c\",\n          \"style\": \"plain\",\n          \"template\": \" {{ round .PhysicalPercentUsed .Precision }}% \",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#b8e994{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#fff34e{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#33DD2D{{end}}\"\n          ],\n          \"foreground\": \"#262626\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\uf240 \",\n            \"charging_icon\": \"\\uf1e6 \",\n            \"discharging_icon\": \"\\ue234 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295 <#262626>\\ue0b2</>\",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"lightGreen\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .CurrentDate | date .Format }}\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"pwd\": \"osc99\",\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/marcduiker.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#feae34\",\n          \"foreground\": \"#262b44\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fee761\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#f77622{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#e43b44{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#2ce8f5{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f77622{{ end }}\"\n          ],\n          \"foreground\": \"#262b44\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#0095e9\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#ff0044{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7 \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/markbull.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffce7b\",\n          \"style\": \"plain\",\n          \"template\": \"\\u250c \",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#ffce7b\",\n          \"foreground\": \"#1d1626\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf26c  {{ if .SSHSession }}\\ueba9  {{ end }}{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#C678DD\",\n          \"foreground\": \"#fffef9\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"windows\": \"\\uf17a\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#C678DD\",\n          \"foreground\": \"#fffef9\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ path .Path .Location }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffffb\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb95{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#fcaf17{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#95ffa4{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f7acbc{{ end }}\",\n            \"{{ if .UpstreamGone }}#d1c7b7{{ end }}\"\n          ],\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"azure_devops_icon\": \"\\uebd8 \",\n            \"bitbucket_icon\": \"\\uf171 \",\n            \"branch_gone_icon\": \"\\uebcc \",\n            \"branch_icon\": \"\\ue0a0 \",\n            \"branch_identical_icon\": \"\\uf4c4 \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true,\n            \"git_icon\": \"\\uf1d3 \",\n            \"github_icon\": \"\\uf408 \",\n            \"gitlab_icon\": \"\\uf296 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if( .UpstreamIcon ) }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} <#ed1941>\\uf044 {{.Working.String}}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} <#225a1f>\\uf046 {{.Staging.String}}</>{{ end }}{{ if gt .StashCount 0 }}  \\ueb4b {{.StashCount}}{{ end }}{{ if gt .WorktreeCount 0 }}{{if .IsWorkTree}}<#1d953f>{{ end }}  \\uf1bb {{if .IsWorkTree}}</>{{ end }}{{.WorktreeCount}}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#33a3dc\",\n          \"foreground\": \"#fffef9\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf064  {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#ed1941\",\n          \"foreground\": \"#fffef9\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf12a >>{{ reason .Code }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffce7b\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2514\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" $\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}\\u26a1 {{end}}{{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/material.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#C591E8>\\u276f</><#69FF94>\\u276f</>\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#D0666F\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#5FAAE8>git:(</>{{ .HEAD }}<#5FAAE8>)</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#DCB977\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf119\",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#66F68F\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/microverse-power.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#3A86FF\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#f1184c\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#f1184c\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"- root \\uf0e7\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#FFBB00\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"time_format\": \"2006-01-02 15:04:05\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#33DD2D\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"\\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#242424\",\n          \"foreground\": \"#3A86FF\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#33DD2D\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#242424\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uea6c \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#f1184c\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/mojada.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#fbfbfb\",\n          \"foreground\": \"#0077c2\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"arch\": \"\\uf303\",\n            \"debian\": \"\\uf306\",\n            \"fedora\": \"\\uf30a\",\n            \"linux\": \"\\uf17c\",\n            \"macos\": \"\\uf179\",\n            \"manjaro\": \"\\uf312\",\n            \"opensuse\": \"\\uf314\",\n            \"ubuntu\": \"\\uf31b\",\n            \"windows\": \"\\uf17a\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#fbfbfb\",\n          \"foreground\": \"#0077c2\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"{{ .UserName }}<#000000>@</><#e06c75>{{ .HostName }}</> \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#e06c75\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue799\\u2800\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"home_icon\": \"~\",\n            \"max_depth\": 2,\n            \"style\": \"letter\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5fe {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#f17c37{{ end }}\",\n            \"{{ if gt .Behind 0 }}#89d1dc{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#FFD54F\",\n          \"style\": \"plain\",\n          \"template\": \" {{if .Root}}#{{else}}${{end}}\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if gt .Code 0 }}\\udb80\\udc30{{ else }}\\uf4a7{{ end }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#f36943\",\n          \"background_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"charged_icon\": \"\\ueb2d \",\n            \"charging_icon\": \"\\uf241 \",\n            \"discharging_icon\": \"\\uf242 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}% \",\n          \"type\": \"battery\"\n        },\n        {\n          \"background\": \"#61afef\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"options\": {\n            \"time_format\": \"15:04 (Mon)\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{.UserName}}@{{.HostName}} : {{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/montys.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#00c983\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .Icon }} {{ .HostName }} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#DA627D\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \"\\\\\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" <#000>\\uf07b \\uea9c</> {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#FCA17D\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \" <#ffffff>\\ue0a0 </>\",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\u279c ({{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#76b367\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#33658A\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"time_format\": \"3:04 PM\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf017 {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}red{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if gt .Code 0 }}\\uf421{{ else }}\\uf469{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#cd5e42\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue3bf \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#CD4277\",\n          \"style\": \"plain\",\n          \"template\": \" <#45F1C2><b>\\u26a1</b></><b>{{ .UserName }}</b> <#26C6DA>\\u276f</><#45F1C2>\\u276f</>\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/mt.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#B4009E\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#FFFF00\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#4E44FF\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\u279c ({{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#4e903d\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#16C60C\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\u2665 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/multiverse-neon.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n     \"segments\": [\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#3EC669\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"mixed\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue5ff {{ .Path }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#29315A\",\n          \"foreground\": \"#43CCEA\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FF9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ff4500{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n            \"{{ if gt .Behind 0 }}#B388FF{{ end }}\"\n          ],\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"git\"\n        },\n\n        {\n          \"foreground\": \"#C94A16\",\n          \"style\": \"plain\",\n          \"template\": \"x \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n     {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"type\": \"node\",\n          \"style\": \"plain\",\n          \"foreground\": \"#88e570\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_package_manager\": true,\n            \"fetch_version\": true,\n            \"bun_icon\": \"<#e5dbcc>\\ue76f bun</>\",\n            \"npm_icon\": \"<#e5272d>\\ue616 npm</> \",\n            \"pnpm_icon\": \"<#e5a100>\\ue865 pnpm</> \",\n            \"yarn_icon\": \"<#37aee5>\\ue6a7 yarn</> \"\n          },\n          \"template\": \"{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}\\ue718 {{ .Full }}\"\n        },\n        {\n          \"foreground\": \"#4063D8\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"crystal\"\n        },\n        {\n          \"foreground\": \"#DE3F24\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"foreground\": \"#FED142\",\n          \"options\": {\n            \"display_mode\": \"context\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"python\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#63F08C\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/negligible.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"cyan\",\n          \"style\": \"powerline\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"cyan\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#F1502F\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \":: {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"red\",\n          \"style\": \"plain\",\n          \"template\": \"| root \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#06A4CE\",\n          \"style\": \"powerline\",\n          \"template\": \"| \\ue798 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"dart\"\n        },\n        {\n          \"foreground\": \"#6CA35E\",\n          \"style\": \"powerline\",\n          \"template\": \"| \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#4584b6\",\n          \"options\": {\n            \"display_mode\": \"context\",\n            \"fetch_virtual_env\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"| \\ue235 {{ .Venv }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#4caf50{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#ff0000{{end}}\"\n          ],\n          \"invert_powerline\": true,\n          \"options\": {\n            \"charged_icon\": \"\\uf00d \",\n            \"charging_icon\": \"\\ue234 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"| {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }} \\uf295 \",\n          \"type\": \"battery\"\n        },\n        {\n          \"foreground\": \"lightGreen\",\n          \"style\": \"plain\",\n          \"template\": \"| {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightGreen\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}red{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \"\\u279c \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/neko.omp.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n    \"blocks\": [\n      {\n        \"alignment\": \"left\",\n        \"segments\": [\n          {\n            \"style\": \"plain\",\n            \"template\": \"😺💬<#FF8000> Meow! What should I do next? ...</>\",\n            \"type\": \"text\"\n          }],\n          \"type\": \"prompt\"\n        },\n      {\n        \"alignment\": \"right\",\n        \"segments\": [\n          {\n            \"foreground\": \"#56B6C2\",\n            \"options\": {\n              \"style\": \"folder\"\n            },\n            \"style\": \"plain\",\n            \"template\": \"🏡 {{ .Path }} \",\n            \"type\": \"path\"\n          },\n          {\n            \"foreground\": \"#D0666F\",\n            \"options\": {\n              \"branch_icon\": \"\",\n              \"fetch_status\": false\n            },\n            \"style\": \"plain\",\n            \"template\":  \"<#5FAAE8>git:(</>{{ .HEAD }}<#5FAAE8>)</>\",\n            \"type\": \"git\"\n          },\n          {\n            \"foreground\": \"#1a415d\",\n\t\t\t\t\t\t\"style\": \"plain\",\n\t\t\t\t\t\t\"template\": \"⌚\",\n\t\t\t\t\t\t\"type\": \"text\"\n\t\t\t\t\t},\n          {\n            \"foreground\": \"#1a415d\",\n            \"options\": {\n              \"time_format\": \"15:04\"\n            },\n            \"style\": \"plain\",\n            \"template\": \" {{ .CurrentDate | date .Format }} \",\n            \"type\": \"time\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n\t\t\t{\n\t\t\t\t\"alignment\": \"left\",\n\t\t\t\t\"segments\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"foreground\": \"#FF8000\",\n\t\t\t\t\t\t\"style\": \"plain\",\n\t\t\t\t\t\t\"template\": \"😀💬<#FF8000> ~ </>\",\n\t\t\t\t\t\t\"type\": \"text\"\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\t\"type\": \"prompt\"\n\t\t\t}\n    ],\n    \"version\": 4\n  }\n"
  },
  {
    "path": "themes/night-owl.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#21c7a8\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b6\",\n          \"options\": {\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}  \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#ef5350\",\n          \"foreground\": \"#ffeb95\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf292 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#82AAFF\",\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"leading_powerline_symbol\": \"\\ue0d7\",\n          \"options\": {\n            \"folder_icon\": \"\\uf07c \",\n            \"folder_separator_icon\": \"<#011627>\\ue0b1</> \",\n            \"home_icon\": \" \\ueb06 \",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \"{{ path .Path .Location }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#addb67\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#e4cf6a{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f78c6c{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#C792EA{{ end }}\",\n            \"{{ if gt .Behind 0 }}#c792ea{{ end }}\"\n          ],\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true,\n            \"mapped_branches\": {\n              \"feat/*\": \"🚀 \",\n              \"bug/*\": \"🐛 \"\n            }\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }} {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#575656\",\n          \"foreground\": \"#d6deeb\",\n          \"leading_diamond\": \"\\ue0d7\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"overflow\": \"break\",\n      \"segments\": [\n        {\n          \"background\": \"#d6deeb\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf489  {{ .Name }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#8f43f3\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue266 {{ round .PhysicalPercentUsed .Precision }}% \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#ce092f\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue753 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"angular\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#de1f84\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\u03b1 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"aurelia\"\n        },\n        {\n          \"background\": \"#565656\",\n          \"foreground\": \"#faa029\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue7ad {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#337bb6\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uebd8 {{ .EnvironmentName }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"az\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#5398c2\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf104<#f5bf45>\\uf0e7</>\\uf105 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background\": \"#5a7a94\",\n          \"foreground\": \"#100e23\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue311  cds {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"cds\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uE370 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"crystal\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#1d5185\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf40a  cf {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"cf\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#1d5185\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf40a {{if .Org }}{{ .Org }}{{ end }}{{ if .Space }}/{{ .Space }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"cftarget\"\n        },\n        {\n          \"background\": \"#d2d2d2\",\n          \"foreground\": \"#01a300\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"<#2829b2>\\ue61e</> <#be1818>\\ue61d</>  cmake {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"cmake\"\n        },\n        {\n          \"background\": \"#e1e8e9\",\n          \"foreground\": \"#055b9c\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue798 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"dart\"\n        },\n        {\n          \"background\": \"#0e0e0e\",\n          \"foreground\": \"#0d6da8\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue77f  {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#06A4CE\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue28e {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"flutter\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#06aad5\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#100e23\",\n          \"foreground\": \"#906cff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue61f {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"haskell\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#ec2729\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"java\"\n        },\n        {\n          \"background\": \"#945bb3\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"<#ca3c34>\\ue624</> {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"K {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"kotlin\"\n        },\n        {\n          \"background\": \"#316ce4\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\uf308 {{.Context}} :: {{if .Namespace}}{{.Namespace}}{{else}}default{{end}} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000081\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue620 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"lua\"\n        },\n        {\n          \"background\": \"#303030\",\n          \"foreground\": \"#3C873A\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \"<#cc3a3a>\\ue71e</> \",\n            \"yarn_icon\": \"<#348cba>\\ue6a7</> \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#6488c0\",\n          \"foreground\": \"#1e293b\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"Nx {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"nx\"\n        },\n        {\n          \"background\": \"#41436d\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue769 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"perl\"\n        },\n        {\n          \"background\": \"#787CB5\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue73d {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"php\"\n        },\n        {\n          \"background\": \"#306998\",\n          \"foreground\": \"#FFE873\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235  {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#b9bbbf\",\n          \"foreground\": \"#1c68bd\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"R {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"r\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#9c1006\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue7a8 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"rust\"\n        },\n        {\n          \"background\": \"#fe562e\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue755 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0d6\",\n          \"type\": \"swift\"\n        },\n        {\n          \"background\": \"#234d70\",\n          \"foreground\": \"#d6deeb\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue641 {{ .CurrentDate | date .Format }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#21c7a8\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#1DB954\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"playing_icon\": \"\\uf1bc \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} ~ {{ .Track }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0c6 \",\n          \"type\": \"spotify\"\n        },\n        {\n          \"foreground\": \"#22da6e\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ef5350{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\ue285\\ue285\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"final_space\": true,\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#d6deeb\",\n    \"template\": \"\\ue285 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/nordtron.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#88c0d0\",\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>\\u250f[</>{{ .UserName }}<#5e81ac>]</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#b48ead\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>--[</>{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<#8fbcbb> \\u25cf </>{{ end }}{{ if .Staging.Changed }}<#88c0d0> \\u25cf </>{{ end }}<#5e81ac>]</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#b48ead\",\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>--[</>{{.Profile}}{{if .Region}}@{{.Region}}{{end}}<#5e81ac>]</>\",\n          \"type\": \"aws\"\n        },\n        {\n          \"foreground\": \"#b48ead\",\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>--[</>{{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}<#5e81ac>]</>\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"foreground\": \"#d8dee9\",\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>[</>\\uf0e7<#5e81ac>]</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#d8dee9\",\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>[x</>{{ reason .Code }}<#5e81ac>]</>\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#88c0d0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#5e81ac>\\u2516[</>{{ .Path }}<#5e81ac>]</>\",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#5e81ac\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue602 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/nu4a.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#cfcfc4\",\n          \"background_templates\": [\n            \"{{if .Root}}#ff3026{{else}}#cfcfc4{{end}}\"\n          ],\n          \"foreground\": \"#100e23\",\n          \"style\": \"powerline\",\n          \"template\": \"{{if .Root}} \\uf0e7 {{.UserName}} {{else}} {{.UserName}} {{end}}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#ec9706\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\ue5ff\",\n            \"folder_separator_icon\": \"\\ue0b9\",\n            \"home_icon\": \"\\ueb06\",\n            \"mapped_locations\": {\n              \"C:\\\\Users\": \"\\uf007\",\n              \"C:\\\\Windows\": \"\\ue62a\"\n            },\n            \"mixed_threshold\": 8,\n            \"style\": \"mixed\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ path .Path .Location }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#3feb56\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#ff4040\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0c2\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue70f \",\n          \"trailing_diamond\": \"\\ue0c0\",\n          \"type\": \"status\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"style\": \"austin\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}} \\u26a1 {{end}}{{.UserName}} \\u2794 📁{{.Folder}}\",\n  \"final_space\": true,\n  \"secondary_prompt\": {\n    \"background\": \"#ec9706\",\n    \"foreground\": \"#100e23\",\n    \"template\": \" \\uf061 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/onehalf.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n    \"black\": \"#282c34\",\n    \"red\": \"#e06c75\",\n    \"green\": \"#98c379\",\n    \"yellow\": \"#e5c07b\",\n    \"blue\": \"#61afef\",\n    \"magenta\": \"#c678dd\",\n    \"cyan\": \"#56b6c2\",\n    \"white\": \"#dcdfe4\",\n    \"foreground\": \"#dcdfe4\",\n    \"background\": \"#282c34\"\n  },\n  \"terminal_background\": \"p:background\",\n  \"console_title_template\": \"{{ .UserName }}@{{ .HostName }}\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"p:yellow\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"p:blue\",\n          \"style\": \"plain\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<p:yellow>git</>:({{ if or (.Working.Changed) (.Staging.Changed) (gt .StashCount 0) }}<p:magenta>{{ .HEAD }}</>{{ else }}<p:green>{{ .HEAD }}</>{{ end }}{{ if (gt .Ahead 0)}}<p:cyan>{{ .BranchStatus }}</>{{ end }}{{ if (gt .Behind 0)}}<p:cyan>{{ .BranchStatus }}</>{{ end }}{{ if .Staging.Changed }} <p:green>{{ .Staging.String }}</>{{ end }}{{ if .Working.Changed }} <p:red>{{ .Working.String }}</>{{ end }})\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"p:foreground\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ if gt .Code 0 }}<p:red>({{ .Code }}) </>{{ else }}<p:green>({{ .Code }}) </>{{ end }}> \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/paradox.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#ffe9aa\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ff8080\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue20f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/pararussel.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#C591E8>\\u276f</><#69FF94>\\u276f</> \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#D0666F\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#5FAAE8>git:(</>{{ .HEAD }}<#5FAAE8>)</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#DCB977\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf119 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf441 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/patriksvensson.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"red\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"blue\",\n          \"options\": {\n            \"folder_icon\": \"\\ue5ff\",\n            \"folder_separator_icon\": \"/\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"green\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}yellow{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}red{{ end }}\",\n            \"{{ if gt .Ahead 0 }}red{{ end }}\",\n            \"{{ if gt .Behind 0 }}green{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true,\n            \"github_icon\": \"\\uf408 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \" on {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<red> \\uf044 {{ .Working.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<yellow> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }}\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"magenta\",\n          \"style\": \"plain\",\n          \"template\": \" [.NET] {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"dotnet\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"yellow\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"green\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/peru.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#0fc469\",\n          \"style\": \"powerline\",\n          \"template\": \"\\u279c \\ue235({{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Major }}.{{ .Minor }}{{ end }}) \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#FFE700\",\n          \"foreground_templates\": [\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#16c60c{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f450de{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ .Full }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738 {{ .Full }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"java\"\n        },\n        {\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if gt .Code 0 }}<#ff0000>\\uf00d</>{{ else }}<#23d18b>\\uf42e</>{{ end }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#bab02a\",\n          \"options\": {\n            \"threshold\": 10\n          },\n          \"style\": \"plain\",\n          \"template\": \"took \\uf252 {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"foreground\": \"#00C5C7\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \\uf017 \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#77E4F7\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#43D426\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/pixelrobots.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#ffea00\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0c7\\u2593\",\n          \"style\": \"diamond\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#ffea00\",\n          \"foreground\": \"#000000\",\n          \"style\": \"powerline\",\n          \"template\": \" \\udb84\\udcfe {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}} \",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"background\": \"#008AD7\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"source\": \"cli\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uebd8 {{ .Name }} [ {{ .Origin }} ] \",\n          \"type\": \"az\"\n        },\n        {\n          \"background\": \"#012456\",\n          \"foreground\": \"#FFFFFF\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"source\": \"pwsh\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uebd8 {{ .Name }} [ {{ .Origin }} ] \",\n          \"type\": \"az\"\n        },\n        {\n          \"type\": \"aws\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\",\n          \"options\": {\n            \"display_default\": true\n          },\n          \"foreground\": \"#000000\",\n          \"background\": \"#FFA400\",\n          \"template\": \" \\udb83\\ude0f {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#26C6DA\",\n          \"leading_diamond\": \"\\ue0c7\\u2593\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}{{ .Icon }} on \\ue62a{{ end }} <#ffea00>\\ue0b1</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffea00\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if ne .Env.POSH_SESSION_DEFAULT_USER .UserName }}{{ .UserName }}{{ end }}<#ffea00> \\ue0b1</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffea00\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7<#ffea00> \\ue0b1</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"options\": {\n            \"folder_icon\": \"<#B5B2C2>\\ue5fe </>\",\n            \"folder_separator_icon\": \"<#ffea00>\\ue0b1 </>\",\n            \"home_icon\": \" \\uf015 \",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#f2f200> \\ue5ff </>{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffea00\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffea00{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#2EC4B6{{ end }}\",\n            \"{{ if gt .Behind 0 }}#8A4FFF{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#ffea00>\\ue0b1 </>{{ .UpstreamIcon }}{{ .HEAD }}{{ .BranchStatus }}{{ if .Working.Changed }}<#E84855> \\uf044 {{ .Working.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#2FDA4E> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffea00\",\n          \"style\": \"plain\",\n          \"template\": \" \\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}root :: {{end}}{{.Shell}} :: {{.Folder}}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/plague.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#333333\",\n          \"foreground\": \"#ff0000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#1BD760\",\n          \"foreground\": \"#434343\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf1bc {{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }} \",\n          \"type\": \"spotify\"\n        },\n        {\n          \"background\": \"#ff0000\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#fffb38\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#6CA35E\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#203248\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf120 {{ .Name }} \",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<transparent>\\ue0b0</> \\ue23a <background,transparent>\\ue0b4</>\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/poshmon.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"diamond\",\n          \"template\": \"\\udb81\\udc1d {{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#D51111\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"home_icon\": \"\\uf46d\",\n            \"folder_separator_icon\": \" <transparent>\\ue0b1</> \",\n            \"folder_icon\": \"\\uf115\",\n            \"style\": \"agnoster\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ path .Path .Location }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#c19c00\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFA300{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#FF7070{{ end }}\",\n            \"{{ if gt .Behind 0 }}#90F090{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf113 {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#303030\",\n          \"foreground\": \"#3C873A\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \" <#cc3a3a>\\ue5fa</> \",\n            \"yarn_icon\": \" <#348cba>\\ue6a7</>\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#306998\",\n          \"foreground\": \"#FFE873\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#06aad5\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4 \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#fff\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#D51111{{ end }}\"\n          ],\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"time_format\": \"_2, 15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf073 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#FFF\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#D51111{{ end }}\"\n          ],\n          \"style\": \"plain\",\n          \"template\": \" \\uf0a4 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"final_space\": true,\n  \"osc99\": true,\n  \"version\": 4\n}\n\n"
  },
  {
    "path": "themes/powerlevel10k_classic.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"plain\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \\ue0b1\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#26C6DA\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#D4E157\",\n          \"style\": \"plain\",\n          \"template\": \"<#26C6DA>\\ue0b1 </>{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"transparent\",\n          \"foreground\": \"#546E7A\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0b0\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#D4E157\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} <#26C6DA>\\ue0b3</> \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#546E7A\",\n          \"foreground\": \"#D4E157\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \\uf017 \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#D4E157\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#FF5252{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/powerlevel10k_lean.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"segments\": [\n        {\n          \"foreground\": \"#00C5C7\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#77E4F7\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#FFE700\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#43D426\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/powerlevel10k_modern.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#0000ff\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#0000ff\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#D4E157\",\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#D4E157\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} <transparent>\\ue0b6</>\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#7FD5EA\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} <transparent>\\ue0b6</>\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#D4E157\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#FF5252{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/powerlevel10k_rainbow.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#d3d7cf\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#3465a4\",\n          \"foreground\": \"#e4e4e4\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"home_icon\": \"~\",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\uf07c {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#4e9a06\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#c4a000{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#4e9a06{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\\uf126 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#689f63\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \\ue718 \",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#00acd7\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue627 \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#4063D8\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue624 \",\n          \"type\": \"julia\"\n        },\n        {\n          \"background\": \"#FFDE57\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue235 \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#AE1401\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\ue791 \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#FEAC19\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \\uf0e7\",\n          \"type\": \"azfunc\"\n        },\n        {\n          \"background_templates\": [\n            \"{{if contains \\\"default\\\" .Profile}}#FFA400{{end}}\",\n            \"{{if contains \\\"jan\\\" .Profile}}#f1184c{{end}}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"display_default\": false\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }} \\ue7ad \",\n          \"type\": \"aws\"\n        },\n        {\n          \"background\": \"#ffff66\",\n          \"foreground\": \"#111111\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0ad \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#c4a000\",\n          \"foreground\": \"#000000\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .FormattedMs }} \\uf252 \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#cc2222{{ end }}\"\n          ],\n          \"foreground\": \"#d3d7cf\",\n          \"invert_powerline\": true,\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if gt .Code 0 }}{{ reason .Code }}{{ else }}\\uf42e{{ end }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"background\": \"#d3d7cf\",\n          \"foreground\": \"#000000\",\n          \"invert_powerline\": true,\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \\uf017 \",\n          \"trailing_diamond\": \"\\ue0b0\\u2500\\u256e\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#d3d7cf\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"segments\": [\n        {\n          \"foreground\": \"#d3d7cf\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2500\\u256f\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} in {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/powerline.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#FFEE58\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ff8080\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue20f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/probua.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#ffdd86\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#42a9ff\",\n          \"style\": \"plain\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"git:{{ if or (.Working.Changed) (.Staging.Changed) (gt .StashCount 0) }}<#ffdd86>{{ .HEAD }}</>{{ else }}{{ .HEAD }}{{ end }}{{ if .Staging.Changed }} <#98c379>{{ .Staging.String }}</>{{ end }}{{ if .Working.Changed }} <#d16971>{{ .Working.String }}</>{{ end }}\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffdd86\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#42a9ff{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"> \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/pure.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#BF616A\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#81A1C1\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#6C6C6C\",\n          \"options\": {\n            \"branch_ahead_icon\": \"<#88C0D0>\\u21e1 </>\",\n            \"branch_behind_icon\": \"<#88C0D0>\\u21e3 </>\",\n            \"branch_icon\": \"\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true,\n            \"github_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<#FFAFD7>*</>{{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#A3BE8C\",\n          \"options\": {\n            \"style\": \"austin\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#B48EAD\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#BF616A{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}(Admin){{end}} {{.PWD}}\",\n  \"transient_prompt\": {\n    \"foreground\": \"#B48EAD\",\n    \"foreground_templates\": [\n      \"{{ if gt .Code 0 }}#BF616A{{ end }}\"\n    ],\n    \"template\": \"\\u276f \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/quick-term.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#d75f00\",\n          \"foreground\": \"#f2f3f8\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b2\",\n          \"template\": \" {{ .Icon }} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#e4e4e4\",\n          \"foreground\": \"#4e4e4e\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"template\": \" {{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#0087af\",\n          \"foreground\": \"#f2f3f8\",\n          \"options\": {\n            \"style\": \"agnoster_short\",\n            \"max_depth\": 3,\n            \"folder_icon\": \"\\u2026\",\n            \"folder_separator_icon\": \" <transparent>\\ue0b1</> \"\n          },\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#378504\",\n          \"foreground\": \"#f2f3f8\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#a97400{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#54433a{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#744d89{{ end }}\",\n            \"{{ if gt .Behind 0 }}#744d89{{ end }}\"\n          ],\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"branch_icon\": \"\\uf418 \",\n            \"branch_identical_icon\": \"\\uf444\",\n            \"branch_gone_icon\": \"\\ueab8\"\n          },\n          \"style\": \"diamond\",\n          \"leading_diamond\": \"<transparent,background>\\ue0b0</>\",\n          \"template\": \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} <transparent>\\ue0b1</> <#121318>\\uf044 {{ .Working.String }}</>{{ end }}{{ if .Staging.Changed }} <transparent>\\ue0b1</> <#121318>\\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} <transparent>\\ue0b1</> <#121318>\\ueb4b {{ .StashCount }}</>{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#e4e4e4\",\n          \"foreground\": \"#585858\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"always_enabled\": true\n          },\n          \"invert_powerline\": true,\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b2\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#d75f00\",\n          \"foreground\": \"#f2f3f8\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"invert_powerline\": true,\n          \"style\": \"diamond\",\n          \"template\": \" \\uf073 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#d75f00\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500 {{ if .Root }}#{{else}}${{end}}\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/remk.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"lightMagenta\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"lightYellow\",\n          \"foreground\": \"#3f3f3f\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"lightCyan\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" git({{ .HEAD }}) \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"lightGreen\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"time_format\": \"15:04\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/robbyrussell.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#98C379\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"  {{ .Path }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#D0666F\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" <#5FAAE8>git:(</>{{ .HEAD }}{{ if .Working.Changed }} <#FFEB3B>{{ .Working.String }}</>{{ end }}<#5FAAE8>)</>{{ if or .Working.Changed .Staging.Changed }} <#FFEB3B>\\u2717</>{{ end }}\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/rudolfs-dark.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#BF231D\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#0A703E\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .Icon }} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#0A703E\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#256C9D\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"folder_icon\": \"\\uf115\",\n            \"folder_separator_icon\": \" \\ue0b1 \",\n            \"max_depth\": 2,\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#256C9D\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 30 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"[ {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} ]\",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#256C9D\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"options\": {\n            \"text\": \"\\ue0b0\"\n          },\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#256C9D\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0b0 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/rudolfs-light.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#BF231D\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#EF7D00\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .Icon }} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#424242\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#424242\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#053F22{{ end }}\",\n            \"{{ if or (gt .Ahead 0) (gt .Behind 0) }}#0A703E{{ end }}\"\n          ],\n          \"options\": {\n            \"branch_template\": \"{{ trunc 30 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" [{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<#BD6200> \\uf044 {{ .Working.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#053F22> \\uf046 {{ .Staging.String }}</>{{ end }}] \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#424242\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#E0E0E0\",\n          \"foreground\": \"#424242\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"options\": {\n            \"text\": \"\\ue0b0\"\n          },\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#E0E0E0\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue0b0 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/schema.json",
    "content": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"$id\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"type\": \"object\",\n  \"title\": \"The Oh My Posh theme definition\",\n  \"description\": \"https://ohmyposh.dev/docs/configuration/general\",\n  \"definitions\": {\n    \"color\": {\n      \"anyOf\": [\n        {\n          \"$ref\": \"#/definitions/color_string\"\n        },\n        {\n          \"$ref\": \"#/definitions/palette_reference\"\n        }\n      ]\n    },\n    \"color_string\": {\n      \"type\": \"string\",\n      \"pattern\": \"^(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})|^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$|black|red|green|yellow|blue|magenta|cyan|white|default|darkGray|lightRed|lightGreen|lightYellow|lightBlue|lightMagenta|lightCyan|lightWhite|transparent|parentBackground|parentForeground|background|foreground|accent)$\",\n      \"title\": \"Color string\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/colors\",\n      \"format\": \"color\"\n    },\n    \"palette_reference\": {\n      \"type\": \"string\",\n      \"pattern\": \"^p:.*$\",\n      \"title\": \"Palette reference\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/colors#palette\"\n    },\n    \"templates\": {\n      \"type\": \"array\",\n      \"title\": \"An array of templates\",\n      \"default\": [],\n      \"items\": {\n        \"$ref\": \"#/definitions/segment/properties/template\"\n      }\n    },\n    \"home_enabled\": {\n      \"type\": \"boolean\",\n      \"title\": \"Enable in the HOME folder\",\n      \"description\": \"Display the segment in the HOME folder\",\n      \"default\": false\n    },\n    \"fetch_version\": {\n      \"type\": \"boolean\",\n      \"title\": \"Fetch Version\",\n      \"description\": \"Fetch the version number\",\n      \"default\": true\n    },\n    \"http_timeout\": {\n      \"type\": \"integer\",\n      \"title\": \"Http request timeout\",\n      \"description\": \"Milliseconds to use for http request timeouts\",\n      \"default\": 20\n    },\n    \"expires_in\": {\n      \"type\": \"integer\",\n      \"title\": \"Expires in\",\n      \"description\": \"Access token expiration time in seconds\",\n      \"default\": 0\n    },\n    \"access_token\": {\n      \"type\": \"string\",\n      \"title\": \"Access token\",\n      \"description\": \"The initial access token\",\n      \"default\": \"\"\n    },\n    \"refresh_token\": {\n      \"type\": \"string\",\n      \"title\": \"Refresh token\",\n      \"description\": \"The initial refresh token\",\n      \"default\": \"\"\n    },\n    \"display_mode\": {\n      \"type\": \"string\",\n      \"title\": \"Display Mode\",\n      \"description\": \"Determines whether the segment is displayed always or only if a file matching the extensions are present in the current folder\",\n      \"enum\": [\n        \"always\",\n        \"files\",\n        \"environment\",\n        \"context\"\n      ],\n      \"default\": \"context\"\n    },\n    \"missing_command_text\": {\n      \"type\": \"string\",\n      \"title\": \"Missing command text\",\n      \"description\": \"The string to display when the command is not available\",\n      \"default\": \"\"\n    },\n    \"status_formats\": {\n      \"type\": \"object\",\n      \"title\": \"Status string formats\",\n      \"description\": \"Override the status format for a specific change. Example: {\\\"Added\\\": \\\"Added: %d\\\"}\",\n      \"default\": {}\n    },\n    \"native_fallback\": {\n      \"type\": \"boolean\",\n      \"title\": \"Native Fallback\",\n      \"description\": \"Try to use the WSL 2 native command in a shared Windows drive if the Windows executable is not found.\",\n      \"default\": false\n    },\n    \"branch_template\": {\n      \"type\": \"string\",\n      \"title\": \"Branch template\",\n      \"description\": \"the temaplate to use for the branch name, supports {{ .Branch }} for the branch name\",\n      \"default\": \"\"\n    },\n    \"mapped_branches\": {\n      \"type\": \"object\",\n      \"title\": \"Mapped Branches\",\n      \"description\": \"Custom glyph/text for specific branches\",\n      \"default\": {}\n    },\n    \"cache_duration\": {\n      \"type\": \"string\",\n      \"title\": \"Cache duration\",\n      \"description\": \"The duration for which the segment will be cached. This is parsed using the `time.ParseDuration` function from the Go standard library (see https://pkg.go.dev/time#ParseDuration for details).\",\n      \"pattern\": \"^(none|infinite|([0-9]+(h|m|s))+)$\"\n    },\n    \"language_options\": {\n      \"type\": \"object\",\n      \"title\": \"Language segment options\",\n      \"description\": \"Common options for language segments\",\n      \"properties\": {\n        \"home_enabled\": {\n          \"$ref\": \"#/definitions/home_enabled\"\n        },\n        \"fetch_version\": {\n          \"$ref\": \"#/definitions/fetch_version\"\n        },\n        \"cache_duration\": {\n          \"$ref\": \"#/definitions/cache_duration\"\n        },\n        \"missing_command_text\": {\n          \"$ref\": \"#/definitions/missing_command_text\"\n        },\n        \"display_mode\": {\n          \"$ref\": \"#/definitions/display_mode\"\n        },\n        \"version_url_template\": {\n          \"type\": \"string\",\n          \"title\": \"Version Url Template\",\n          \"description\": \"Template that creates the URL of the version info / release notes\",\n          \"default\": \"\"\n        },\n        \"tooling\": {\n          \"type\": \"array\",\n          \"title\": \"Tooling\",\n          \"description\": \"The tooling to use for fetching the version\",\n          \"default\": [],\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"extensions\": {\n          \"type\": \"array\",\n          \"title\": \"Extensions\",\n          \"description\": \"The extensions to look for when determining if the current directory is a project\",\n          \"default\": [],\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"folders\": {\n          \"type\": \"array\",\n          \"title\": \"Folders\",\n          \"description\": \"The folders to look for when determining if a folder is a workspace\",\n          \"default\": [],\n          \"items\": {\n            \"type\": \"string\"\n          }\n        }\n      }\n    },\n    \"filler\": {\n      \"type\": \"string\",\n      \"title\": \"Filler\",\n      \"description\": \"Right aligned filler text, will span the remaining width.\"\n    },\n    \"aliases\": {\n      \"type\": \"object\",\n      \"title\": \"Aliases\",\n      \"description\": \"Custom value replacement for template parts\",\n      \"default\": {}\n    },\n    \"extra_prompt\": {\n      \"type\": \"object\",\n      \"default\": {},\n      \"properties\": {\n        \"template\": {\n          \"type\": \"string\",\n          \"title\": \"Prompt Template\"\n        },\n        \"foreground\": {\n          \"$ref\": \"#/definitions/color\"\n        },\n        \"foreground_templates\": {\n          \"$ref\": \"#/definitions/templates\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/colors#color-templates\"\n        },\n        \"background\": {\n          \"$ref\": \"#/definitions/color\"\n        },\n        \"background_templates\": {\n          \"$ref\": \"#/definitions/templates\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/colors#color-templates\"\n        }\n      }\n    },\n    \"block\": {\n      \"type\": \"object\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/block\",\n      \"allOf\": [\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"prompt\"\n              }\n            }\n          },\n          \"then\": {\n            \"required\": [\n              \"type\",\n              \"alignment\",\n              \"segments\"\n            ],\n            \"title\": \"Prompt definition, contains 1 or more segments to render\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"rprompt\"\n              }\n            }\n          },\n          \"then\": {\n            \"required\": [\n              \"type\",\n              \"segments\"\n            ],\n            \"title\": \"RPrompt definition, contains 1 or more segments to render to the right of the cursor\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"prompt\"\n              },\n              \"alignment\": {\n                \"const\": \"right\"\n              }\n            }\n          },\n          \"then\": {\n            \"properties\": {\n              \"overflow\": {\n                \"type\": \"string\",\n                \"title\": \"Block overflow\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/block#overflow\",\n                \"enum\": [\n                  \"break\",\n                  \"hide\"\n                ],\n                \"default\": \"\"\n              },\n              \"filler\": {\n                \"$ref\": \"#/definitions/filler\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/block#filler\"\n              }\n            }\n          }\n        }\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"Block type\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#type\",\n          \"enum\": [\n            \"prompt\",\n            \"rprompt\"\n          ],\n          \"default\": \"prompt\"\n        },\n        \"alignment\": {\n          \"type\": \"string\",\n          \"title\": \"Block alignment\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#alignment\",\n          \"enum\": [\n            \"left\",\n            \"right\"\n          ],\n          \"default\": \"left\"\n        },\n        \"newline\": {\n          \"type\": \"boolean\",\n          \"title\": \"Newline\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#newline\",\n          \"default\": false\n        },\n        \"filler\": {\n          \"type\": \"string\",\n          \"title\": \"Filler\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#filler\",\n          \"default\": \"\"\n        },\n        \"overflow\": {\n          \"type\": \"string\",\n          \"title\": \"Overflow\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#overflow\",\n          \"default\": \"\"\n        },\n        \"leading_diamond\": {\n          \"type\": \"string\",\n          \"title\": \"Leading diamond\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#leading-diamond\",\n          \"default\": \"\"\n        },\n        \"trailing_diamond\": {\n          \"type\": \"string\",\n          \"title\": \"Trailing diamond\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#trailing-diamond\",\n          \"default\": \"\"\n        },\n        \"segments\": {\n          \"type\": \"array\",\n          \"title\": \"Segments list, prompt elements to display based on context\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#segments\",\n          \"default\": [],\n          \"items\": {\n            \"$ref\": \"#/definitions/segment\"\n          }\n        },\n        \"force\": {\n          \"type\": \"boolean\",\n          \"title\": \"Force\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#force\",\n          \"default\": false\n        },\n        \"index\": {\n          \"type\": \"integer\",\n          \"title\": \"Index\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/block#index\"\n        }\n      }\n    },\n    \"segment\": {\n      \"type\": \"object\",\n      \"title\": \"Segment\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n      \"default\": {},\n      \"required\": [\n        \"type\",\n        \"style\"\n      ],\n      \"properties\": {\n        \"type\": {\n          \"type\": \"string\",\n          \"title\": \"Segment Type\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"enum\": [\n            \"angular\",\n            \"argocd\",\n            \"aurelia\",\n            \"aws\",\n            \"az\",\n            \"azd\",\n            \"azfunc\",\n            \"battery\",\n            \"bazel\",\n            \"brewfather\",\n            \"buf\",\n            \"bun\",\n            \"carbonintensity\",\n            \"cds\",\n            \"cf\",\n            \"cftarget\",\n            \"claude\",\n            \"clojure\",\n            \"cmake\",\n            \"copilot\",\n            \"connection\",\n            \"crystal\",\n            \"dart\",\n            \"deno\",\n            \"docker\",\n            \"dotnet\",\n            \"elixir\",\n            \"executiontime\",\n            \"firebase\",\n            \"flutter\",\n            \"fortran\",\n            \"fossil\",\n            \"gcp\",\n            \"git\",\n            \"gitversion\",\n            \"go\",\n            \"haskell\",\n            \"helm\",\n            \"http\",\n            \"ipify\",\n            \"java\",\n            \"jujutsu\",\n            \"julia\",\n            \"kotlin\",\n            \"kubectl\",\n            \"lastfm\",\n            \"lua\",\n            \"mercurial\",\n            \"mojo\",\n            \"mvn\",\n            \"nba\",\n            \"nbgv\",\n            \"nightscout\",\n            \"nim\",\n            \"nix-shell\",\n            \"node\",\n            \"npm\",\n            \"nx\",\n            \"ocaml\",\n            \"os\",\n            \"owm\",\n            \"path\",\n            \"perl\",\n            \"php\",\n            \"plastic\",\n            \"pnpm\",\n            \"project\",\n            \"pulumi\",\n            \"python\",\n            \"quasar\",\n            \"r\",\n            \"ramadan\",\n            \"react\",\n            \"root\",\n            \"ruby\",\n            \"rust\",\n            \"sapling\",\n            \"session\",\n            \"shell\",\n            \"sitecore\",\n            \"spotify\",\n            \"status\",\n            \"strava\",\n            \"svelte\",\n            \"svn\",\n            \"swift\",\n            \"sysinfo\",\n            \"talosctl\",\n            \"taskwarrior\",\n            \"tauri\",\n            \"terraform\",\n            \"text\",\n            \"time\",\n            \"todoist\",\n            \"ui5tooling\",\n            \"umbraco\",\n            \"unity\",\n            \"upgrade\",\n            \"v\",\n            \"vala\",\n            \"wakatime\",\n            \"winget\",\n            \"winreg\",\n            \"withings\",\n            \"xmake\",\n            \"yarn\",\n            \"ytm\",\n            \"zig\"\n          ]\n        },\n        \"style\": {\n          \"title\": \"Segment Style\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment#style\",\n          \"anyOf\": [\n            {\n              \"enum\": [\n                \"plain\",\n                \"powerline\",\n                \"diamond\",\n                \"accordion\"\n              ]\n            },\n            {\n              \"type\": \"string\"\n            }\n          ]\n        },\n        \"foreground\": {\n          \"$ref\": \"#/definitions/color\"\n        },\n        \"foreground_templates\": {\n          \"$ref\": \"#/definitions/templates\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/colors#color-templates\"\n        },\n        \"background\": {\n          \"$ref\": \"#/definitions/color\"\n        },\n        \"background_templates\": {\n          \"$ref\": \"#/definitions/templates\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/colors#color-templates\"\n        },\n        \"template\": {\n          \"type\": \"string\",\n          \"title\": \"Template text\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/templates\",\n          \"default\": \"\"\n        },\n        \"templates_logic\": {\n          \"type\": \"string\",\n          \"title\": \"Templates Logic\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"enum\": [\n            \"first_match\",\n            \"join\"\n          ]\n        },\n        \"max_width\": {\n          \"type\": \"integer\",\n          \"title\": \"if the terminal width exceeds this value, the segment will be hidden\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"default\": 0\n        },\n        \"min_width\": {\n          \"type\": \"integer\",\n          \"title\": \"if the terminal width is inferior than this value, the segment will be hidden\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"default\": 0\n        },\n        \"options\": {\n          \"type\": \"object\",\n          \"title\": \"Segment options, used to change behavior/displaying\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment#options\",\n          \"default\": {}\n        },\n        \"properties\": {\n          \"type\": \"object\",\n          \"title\": \"Segment Properties (DEPRECATED)\",\n          \"description\": \"DEPRECATED: Use 'options' instead. This field is maintained for backward compatibility with version 3 configs and will be removed in a future version. See https://ohmyposh.dev/docs/configuration/segment#options\",\n          \"default\": {},\n          \"deprecated\": true,\n          \"deprecationMessage\": \"The 'properties' field is deprecated. Please rename it to 'options' in your configuration.\"\n        },\n        \"interactive\": {\n          \"type\": \"boolean\",\n          \"title\": \"Allow the use of interactive prompt escape sequences\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"default\": false\n        },\n        \"alias\": {\n          \"type\": \"string\",\n          \"title\": \"Give the segment an alias for use in templates\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment\",\n          \"default\": \"\"\n        },\n        \"include_folders\": {\n          \"type\": \"array\",\n          \"title\": \"If specified, segment will only render in these folders\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment#include--exclude-folders\",\n          \"default\": [],\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"exclude_folders\": {\n          \"type\": \"array\",\n          \"title\": \"Exclude rendering in these folders\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment#include--exclude-folders\",\n          \"default\": [],\n          \"items\": {\n            \"type\": \"string\"\n          }\n        },\n        \"cache\": {\n          \"type\": \"object\",\n          \"title\": \"Cache settings\",\n          \"description\": \"https://ohmyposh.dev/docs/configuration/segment#cache\",\n          \"default\": {},\n          \"properties\": {\n            \"duration\": {\n              \"$ref\": \"#/definitions/cache_duration\"\n            },\n            \"strategy\": {\n              \"type\": \"string\",\n              \"title\": \"Cache strategy\",\n              \"description\": \"https://ohmyposh.dev/docs/configuration/segment#strategy\",\n              \"default\": \"folder\",\n              \"enum\": [\n                \"folder\",\n                \"session\",\n                \"device\"\n              ]\n            }\n          }\n        },\n        \"placeholder\": {\n          \"type\": \"string\",\n          \"title\": \"Placeholder text\",\n          \"description\": \"Text to display while the segment is loading in streaming mode. See https://ohmyposh.dev/docs/experimental/streaming\",\n          \"default\": \"...\"\n        }\n      },\n      \"allOf\": [\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"angular\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Angular CLI Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/angular\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"angular.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"angular\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"argocd\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"ArgoCD Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/argocd\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"aurelia\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Aurelia Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/aurelia\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"package.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"aurelia\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"aws\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"AWS Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/aws\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_default\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Default User Profile\",\n                    \"description\": \"Display the segment when default user or not\",\n                    \"default\": true\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"az\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Azure Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/az\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"source\": {\n                    \"type\": \"string\",\n                    \"title\": \"Source\",\n                    \"description\": \"https://ohmyposh.dev/docs/segments/cloud/az#options\",\n                    \"default\": \"first_match\",\n                    \"enum\": [\n                      \"cli\",\n                      \"pwsh\"\n                    ]\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"azd\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Azure Developer CLI Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/azd\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"azfunc\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Azure Function Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/azfunc\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"host.json\",\n                      \"local.settings.json\",\n                      \"function.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"func\"\n                    ]\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"battery\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Battery Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/battery\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_error\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Error\",\n                    \"description\": \"Show the error context when failing to retrieve the battery information\",\n                    \"default\": false\n                  },\n                  \"charging_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Charging Icon\",\n                    \"description\": \"Text/icon to display when charging\",\n                    \"default\": \"\"\n                  },\n                  \"discharging_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"discharging Dcon\",\n                    \"description\": \"Text/icon to display when discharging\",\n                    \"default\": \"\"\n                  },\n                  \"charged_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Charged Icon\",\n                    \"description\": \"Text/icon to display when fully charged\",\n                    \"default\": \"\"\n                  },\n                  \"not_charging_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Not Charging Icon\",\n                    \"description\": \"Text/icon to display when on AC power\",\n                    \"default\": \"\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"bazel\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Bazel Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/bazel\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.bazel\",\n                      \"*.bzl\",\n                      \"BUILD\",\n                      \"WORKSPACE\",\n                      \".bazelrc\",\n                      \".bazelversion\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \"bazel-bin\",\n                      \"bazel-out\",\n                      \"bazel-testlogs\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"bazel\"\n                    ]\n                  },\n                  \"icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon\",\n                    \"description\": \"The icon representing Bazel's logo\",\n                    \"default\": \"\\ue63a\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"brewfather\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Brewfather Batch Status\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/brewfather\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"user_id\": {\n                    \"type\": \"string\",\n                    \"title\": \"Brewfather UserID (required)\",\n                    \"description\": \"Provided by Brewfather's Generate API Key settings option\",\n                    \"default\": \"\"\n                  },\n                  \"api_key\": {\n                    \"type\": \"string\",\n                    \"title\": \"Brewfather API Key (required)\",\n                    \"description\": \"Provided by Brewfather's Generate API Key settings option\",\n                    \"default\": \"\"\n                  },\n                  \"batch_id\": {\n                    \"type\": \"string\",\n                    \"title\": \"ID of the batch in Brewfather (required)\",\n                    \"description\": \"At the end of the URL when viewing the batch on the Brewfather site\",\n                    \"default\": \"\"\n                  },\n                  \"day_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon to use to indicate days\",\n                    \"description\": \"Appended to a number to indicate days, e.g. 25d\",\n                    \"default\": \"d\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  },\n                  \"doubleup_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, very high positive change\",\n                    \"description\": \"Delta between this and prior temperature reading is very high (> 4C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2191\\u2191\"\n                  },\n                  \"singleup_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, high positive change\",\n                    \"description\": \"Delta between this and prior temperature reading is high (2C < delta < 4C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2191\"\n                  },\n                  \"fortyfiveup_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, positive change\",\n                    \"description\": \"Delta between this and prior temperature reading is positive (0.5C < delta < 2C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2197\"\n                  },\n                  \"flat_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, flat/small change\",\n                    \"description\": \"Delta between this and prior temperature and this temperature reading (< +-0.5C change), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2192\"\n                  },\n                  \"fortyfivedown_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, v. negative change\",\n                    \"description\": \"Delta between this and prior temperature reading is negative (-0.5C > delta > -2C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2198\"\n                  },\n                  \"singledown_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, high negative change\",\n                    \"description\": \"Delta between this and prior temperature reading is large negative (-2C > delta > -4C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2193\"\n                  },\n                  \"doubledown_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Temperature trend icon, very high negative change\",\n                    \"description\": \"Delta between this and prior temperature reading is very large negative (> -4C by default), available intemplate as .TemperatureTrend\",\n                    \"default\": \"\\u2193\\u2193\"\n                  },\n                  \"planning_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for batch in planning\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\uf8ea\"\n                  },\n                  \"brewing_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for batch being brewed\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\uf7de\"\n                  },\n                  \"fermenting_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for batch fermenting\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\uf499\"\n                  },\n                  \"conditioning_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for batch conditioning\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\ue372\"\n                  },\n                  \"completed_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for completed batch\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\uf7a5\"\n                  },\n                  \"archived_status_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Icon for archived batch\",\n                    \"description\": \"Available in template as .StatusIcon\",\n                    \"default\": \"\\uf187\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"buf\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Buf Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/buf\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"buf.yaml\",\n                      \"buf.gen.yaml\",\n                      \"buf.work.yaml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"buf\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"bun\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Bun CLI Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/bun\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"bun.lockb\",\n                      \"bun.lock\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"bun\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"carbonintensity\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Carbon Intensity Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/carbonintensity\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"cds\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"CDS (SAP CAP) segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/cds\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \".cdsrc.json\",\n                      \".cdsrc-private.json\",\n                      \"*.cds\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"cds\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"cf\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Clound Foundry CLI segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/cf\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"manifest.yml\",\n                      \"mta.yaml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"cf\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"cftarget\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Clound Foundry Target segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/cftarget\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_mode\": {\n                    \"$ref\": \"#/definitions/display_mode\",\n                    \"enum\": [\n                      \"always\",\n                      \"files\"\n                    ],\n                    \"default\": \"always\"\n                  },\n                  \"files\": {\n                    \"type\": \"array\",\n                    \"title\": \"Files\",\n                    \"description\": \"The files to display in the segment\",\n                    \"default\": [\n                      \"manifest.yml\"\n                    ],\n                    \"items\": {\n                      \"type\": \"string\"\n                    }\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"clojure\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Clojure Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/clojure\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"project.clj\",\n                      \"deps.edn\",\n                      \"build.boot\",\n                      \"bb.edn\",\n                      \"*.clj\",\n                      \"*.cljc\",\n                      \"*.cljs\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"clojure\",\n                      \"lein\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"cmake\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Cmake Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/cmake\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.cmake\",\n                      \"CMakeLists.txt\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"cmake\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"claude\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Claude Code Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/claude\",\n            \"properties\": {\n              \"options\": {\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"copilot\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"GitHub Copilot Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/copilot\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"connection\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Connection Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/connection\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"type\": {\n                    \"type\": \"string\",\n                    \"title\": \"Connection type\",\n                    \"description\": \"The connection type to display\",\n                    \"enum\": [\n                      \"ethernet\",\n                      \"wifi\",\n                      \"cellular\",\n                      \"bluetooth\"\n                    ],\n                    \"default\": \"wifi|ethernet\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"crystal\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Crystal Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/crystal\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.cr\",\n                      \"shard.yml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"crystal\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"dart\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Dart Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/dart\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.dart\",\n                      \"pubspec.yaml\",\n                      \"pubspec.yml\",\n                      \"pubspec.lock\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \".dart_tool\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"fvm\",\n                      \"dart\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"deno\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Deno CLI Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/deno\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.js\",\n                      \"*.ts\",\n                      \"deno.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"deno\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"style\": {\n                \"const\": \"diamond\"\n              }\n            }\n          },\n          \"then\": {\n            \"properties\": {\n              \"leading_diamond\": {\n                \"type\": \"string\",\n                \"title\": \"Leading diamond\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/segment#leading-diamond\",\n                \"default\": \"\"\n              },\n              \"trailing_diamond\": {\n                \"type\": \"string\",\n                \"title\": \"Trailing diamond\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/segment#trailing-diamond\",\n                \"default\": \"\"\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"docker\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Docker Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/docker\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_mode\": {\n                    \"$ref\": \"#/definitions/display_mode\",\n                    \"enum\": [\n                      \"files\",\n                      \"context\"\n                    ]\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"compose.yml\",\n                      \"compose.yaml\",\n                      \"docker-compose.yml\",\n                      \"docker-compose.yaml\",\n                      \"Dockerfile\"\n                    ]\n                  },\n                  \"fetch_context\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Context\",\n                    \"description\": \"Fetch the Docker context\",\n                    \"default\": true\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"dotnet\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Dotnet Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/dotnet\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.cs\",\n                      \"*.csx\",\n                      \"*.vb\",\n                      \"*.fs\",\n                      \"*.fsx\",\n                      \"*.sln\",\n                      \"*.slnf\",\n                      \"*.slnx\",\n                      \"*.csproj\",\n                      \"*.fsproj\",\n                      \"*.vbproj\",\n                      \"global.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"dotnet\"\n                    ]\n                  },\n                  \"fetch_sdk_version\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch SDK Version\",\n                    \"description\": \"Fetch the .NET SDK version used in global.json\",\n                    \"default\": false\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"elixir\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Elixir Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/elixir\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.ex\",\n                      \"*.exs\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"asdf\",\n                      \"elixir\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"executiontime\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Displays the execution time of the previously executed command\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/executiontime\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"always_enabled\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Always Enabled\",\n                    \"description\": \"Always show the duration\",\n                    \"default\": false\n                  },\n                  \"threshold\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Threshold\",\n                    \"description\": \"minimum duration (milliseconds) required to enable this segment\",\n                    \"default\": 500\n                  },\n                  \"style\": {\n                    \"type\": \"string\",\n                    \"title\": \"Style\",\n                    \"description\": \"The style in which the time will be displayed\",\n                    \"enum\": [\n                      \"austin\",\n                      \"roundrock\",\n                      \"dallas\",\n                      \"galveston\",\n                      \"galvestonms\",\n                      \"houston\",\n                      \"amarillo\",\n                      \"round\",\n                      \"lucky7\"\n                    ],\n                    \"default\": \"austin\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"firebase\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Firebase Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/firebase\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"flutter\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Flutter Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/flutter\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.dart\",\n                      \"pubspec.yaml\",\n                      \"pubspec.yml\",\n                      \"pubspec.lock\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \".dart_tool\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"fvm\",\n                      \"flutter\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"fortran\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Fortran Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/fortran\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"fpm.toml\",\n                      \"*.f\",\n                      \"*.for\",\n                      \"*.fpp\",\n                      \"*.f77\",\n                      \"*.f90\",\n                      \"*.f95\",\n                      \"*.f03\",\n                      \"*.f08\",\n                      \"*.F\",\n                      \"*.FOR\",\n                      \"*.FPP\",\n                      \"*.F77\",\n                      \"*.F90\",\n                      \"*.F95\",\n                      \"*.F03\",\n                      \"*.F08\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"gfortran\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"fossil\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Fossil Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/fossil\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"gcp\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"GCP Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/gcp\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"git\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Git Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/git\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the local changes or not\",\n                    \"default\": false\n                  },\n                  \"fetch_push_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Push Status\",\n                    \"description\": \"Display the push-remote ahead/behind information or not\",\n                    \"default\": false\n                  },\n                  \"fetch_upstream_icon\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Upstream Icon\",\n                    \"description\": \"Display upstream icon or not\",\n                    \"default\": false\n                  },\n                  \"fetch_bare_info\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch info when in a bare repo\",\n                    \"description\": \"Fetch info when in a bare repo or not\",\n                    \"default\": false\n                  },\n                  \"fetch_user\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch the user\",\n                    \"description\": \"Fetch the current configured user for the repository\",\n                    \"default\": false\n                  },\n                  \"disable_with_jj\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Disable with Jujutsu\",\n                    \"description\": \"Disable the git segment when there's a .jj directory in the parent file path\",\n                    \"default\": false\n                  },\n                  \"branch_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Icon\",\n                    \"description\": \"The icon to use in front of the git branch name\",\n                    \"default\": \"\\ue0a0 \"\n                  },\n                  \"branch_identical_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Identical Icon\",\n                    \"description\": \"The icon to display when remote and local are identical\",\n                    \"default\": \"\\u2261\"\n                  },\n                  \"branch_ahead_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Ahead Icon\",\n                    \"description\": \"The icon to display when the local branch is ahead of its remote\",\n                    \"default\": \"\\u2191\"\n                  },\n                  \"branch_behind_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Behind Icon\",\n                    \"description\": \"The icon to display when the local branch is behind its remote\",\n                    \"default\": \"\\u2193\"\n                  },\n                  \"branch_gone_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Gone Icon\",\n                    \"description\": \"The icon to display when there's no remote branch\",\n                    \"default\": \"\\u2262\"\n                  },\n                  \"commit_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Commit Icon\",\n                    \"description\": \"Icon/text to display before the commit context (detached HEAD)\",\n                    \"default\": \"\\uf417\"\n                  },\n                  \"tag_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Tag Icon\",\n                    \"description\": \"Icon/text to display before the tag context\",\n                    \"default\": \"\\uf412\"\n                  },\n                  \"rebase_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Rebase Icon\",\n                    \"description\": \"Icon/text to display before the context when in a rebase\",\n                    \"default\": \"\\ue728\"\n                  },\n                  \"cherry_pick_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Cherry-pick Icon\",\n                    \"description\": \"Icon/text to display before the context when doing a cherry-pick\",\n                    \"default\": \"\\ue29b\"\n                  },\n                  \"revert_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Revert Icon\",\n                    \"description\": \"Icon/text to display before the context when doing a revert\",\n                    \"default\": \"\\uf0e2\"\n                  },\n                  \"merge_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Merge Icon\",\n                    \"description\": \"Icon/text to display before the merge context\",\n                    \"default\": \"\\ue727\"\n                  },\n                  \"no_commits_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"No Commits Icon\",\n                    \"description\": \"Icon/text to display when there are no commits in the repo\",\n                    \"default\": \"\\uf594\"\n                  },\n                  \"github_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"GitHub Icon\",\n                    \"description\": \"Icon/text to display when the upstream is GitHub\",\n                    \"default\": \"\\uf408\"\n                  },\n                  \"gitlab_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"GitLab Icon\",\n                    \"description\": \"Icon/text to display when the upstream is GitLab\",\n                    \"default\": \"\\uf296\"\n                  },\n                  \"bitbucket_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Bitbucket Icon\",\n                    \"description\": \"Icon/text to display when the upstream is Bitbucket\",\n                    \"default\": \"\\uf171\"\n                  },\n                  \"azure_devops_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Azure DevOps Icon\",\n                    \"description\": \"Icon/text to display when the upstream is Azure DevOps\",\n                    \"default\": \"\\uebe8\"\n                  },\n                  \"codecommit_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"CodeCommit Icon\",\n                    \"description\": \"Icon/text to display when the upstream is CodeCommit\",\n                    \"default\": \"\\uf270\"\n                  },\n                  \"codeberg_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Codeberg Icon\",\n                    \"description\": \"Icon/text to display when the upstream is Codeberg\",\n                    \"default\": \"\\uf330\"\n                  },\n                  \"git_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Git Icon\",\n                    \"description\": \"Icon/text to display when the upstream is not known/mapped\",\n                    \"default\": \"\\ue5fb\"\n                  },\n                  \"upstream_icons\": {\n                    \"type\": \"object\",\n                    \"title\": \"Status string formats\",\n                    \"description\": \"a key, value map representing the remote URL (or a part of that URL) and icon to use in case the upstream URL contains the key. These get precedence over the standard icons\",\n                    \"default\": {}\n                  },\n                  \"untracked_modes\": {\n                    \"type\": \"object\",\n                    \"title\": \"Untracked files mode\",\n                    \"description\": \"Set the untracked files mode for a repository\",\n                    \"default\": {}\n                  },\n                  \"ignore_submodules\": {\n                    \"type\": \"object\",\n                    \"title\": \"Ignore submodules\",\n                    \"description\": \"Ignore changes to submodules when looking for changes\",\n                    \"default\": {}\n                  },\n                  \"ignore_status\": {\n                    \"type\": \"array\",\n                    \"title\": \"Ignore fetching status in these repo's\",\n                    \"description\": \"Ignore fetching status for certain repo's, uses the same logic as the exclude_folders property\",\n                    \"default\": [],\n                    \"items\": {\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  },\n                  \"mapped_branches\": {\n                    \"$ref\": \"#/definitions/mapped_branches\"\n                  },\n                  \"branch_template\": {\n                    \"$ref\": \"#/definitions/branch_template\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"gitversion\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Display GitVersion segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/gitversion\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"go\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Golang Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/golang\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"parse_mod_file\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Parse go.mod file\",\n                    \"description\": \"Parse go.mod file instead of calling out to go to improve performance.\",\n                    \"default\": false\n                  },\n                  \"parse_go_work_file\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Parse go.work file\",\n                    \"description\": \"Parse go.work file instead of calling out to go to improve performance.\",\n                    \"default\": false\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.go\",\n                      \"go.mod\",\n                      \"go.work\",\n                      \"go.sum\",\n                      \"go.work.sum\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"mod\",\n                      \"go\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"haskell\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Haskell Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/haskell\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"stack_ghc_mode\": {\n                    \"type\": \"string\",\n                    \"title\": \"Use Stack GHC\",\n                    \"description\": \"Get the GHC version used by Stack. Will decrease performance. Boolean indicating whether stack ghc was used available in template as .StackGhc\",\n                    \"enum\": [\n                      \"always\",\n                      \"package\",\n                      \"never\"\n                    ],\n                    \"default\": \"never\"\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.hs\",\n                      \"*.lhs\",\n                      \"stack.yaml\",\n                      \"package.yaml\",\n                      \"*.cabal\",\n                      \"cabal.project\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"ghc\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"helm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Helm segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/helm\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_mode\": {\n                    \"$ref\": \"#/definitions/display_mode\",\n                    \"enum\": [\n                      \"always\",\n                      \"files\"\n                    ],\n                    \"default\": \"always\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"http\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"HTTP segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/http\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"url\": {\n                    \"type\": \"string\",\n                    \"title\": \"URL\",\n                    \"description\": \"The HTTP URL you want to call, supports templates\",\n                    \"default\": \"\"\n                  },\n                  \"method\": {\n                    \"type\": \"string\",\n                    \"title\": \"HTTP Method\",\n                    \"description\": \"The HTTP method to use\",\n                    \"enum\": [\n                      \"GET\",\n                      \"POST\"\n                    ],\n                    \"default\": \"GET\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ipify\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Display your external IP Address\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/ipify\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"url\": {\n                    \"type\": \"string\",\n                    \"title\": \"URL\",\n                    \"description\": \"The Ipify API URL\",\n                    \"default\": \"https://api.ipify.org\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  },\n                  \"cache_duration\": {\n                    \"$ref\": \"#/definitions/cache_duration\",\n                    \"default\": \"24h\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"java\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Java Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/java\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"pom.xml\",\n                      \"build.gradle.kts\",\n                      \"build.sbt\",\n                      \".java-version\",\n                      \".deps.edn\",\n                      \"project.clj\",\n                      \"build.boot\",\n                      \"*.java\",\n                      \"*.class\",\n                      \"*.gradle\",\n                      \"*.jar\",\n                      \"*.clj\",\n                      \"*.cljc\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"java\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"jujutsu\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Jujutsu Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/jujutsu\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"change_id_min_len\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Change ID Minimum Length\",\n                    \"description\": \"Minimum length of the change ID to display\",\n                    \"default\": 0\n                  },\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the changes in the working copy\",\n                    \"default\": false\n                  },\n                  \"ignore_working_copy\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Ignore Working Copy\",\n                    \"description\": \"Don't snapshot the working copy, and don't update it\",\n                    \"default\": true\n                  },\n                  \"fetch_ahead_counter\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Ahead Counter\",\n                    \"description\": \"Fetch working copy # of changes ahead of the nearest bookmark\",\n                    \"default\": false\n                  },\n                  \"ahead_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Ahead icon\",\n                    \"description\": \"Icon to separate bookmark name and ahead counter\",\n                    \"default\": \"\\u21e1\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"julia\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Julia Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/julia\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.jl\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"julia\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"kotlin\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Kotlin Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/kotlin\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.kt\",\n                      \"*.kts\",\n                      \"*.ktm\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"kotlin\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"kubectl\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Kubectl Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/kubectl\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_error\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Error\",\n                    \"description\": \"Show the error context when failing to retrieve the kubectl information\",\n                    \"default\": false\n                  },\n                  \"parse_kubeconfig\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Parse kubeconfig\",\n                    \"description\": \"Parse kubeconfig files instead of calling out to kubectl to improve performance.\",\n                    \"default\": true\n                  },\n                  \"context_aliases\": {\n                    \"type\": \"object\",\n                    \"title\": \"Context aliases\",\n                    \"description\": \"Custom context names.\",\n                    \"default\": {}\n                  },\n                  \"cluster_aliases\": {\n                    \"type\": \"object\",\n                    \"title\": \"Cluster aliases\",\n                    \"description\": \"Custom cluster names.\",\n                    \"default\": {}\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"lastfm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"LastFM Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/music/lastfm\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"playing_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Playing Icon\",\n                    \"description\": \"Text/icon to show when playing\",\n                    \"default\": \"\\ue602 \"\n                  },\n                  \"stopped_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Stopped Icon\",\n                    \"description\": \"Text/icon to show when stopped\",\n                    \"default\": \"\\uf04d \"\n                  },\n                  \"api_key\": {\n                    \"type\": \"string\",\n                    \"title\": \"API key\",\n                    \"description\": \"The API key used for the API call (Required)\",\n                    \"default\": \".\"\n                  },\n                  \"username\": {\n                    \"type\": \"string\",\n                    \"title\": \"username\",\n                    \"description\": \"The username used for the API call (Required)\",\n                    \"default\": \".\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"lua\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Lua Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/lua\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.lua\",\n                      \"*.rockspec\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \"lua\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"lua\",\n                      \"luajit\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"mercurial\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Mercurial Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/mercurial\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the local changes or not\",\n                    \"default\": false\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"mojo\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Mojo Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/mojo\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"fetch_virtual_env\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Virtual Env\",\n                    \"description\": \"Fetch the name of the virtualenv or not\",\n                    \"default\": true\n                  },\n                  \"display_default\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Default\",\n                    \"description\": \"Show the name of the virtualenv when it's default\",\n                    \"default\": true\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.🔥\",\n                      \"*.mojo\",\n                      \"mojoproject.toml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"mojo\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"mvn\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Maven Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/mvn\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"pom.xml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"mvn\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nbgv\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Nerdbank.GitVersion Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/nbgv\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nightscout\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Display Nightscout segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/health/nightscout\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"url\": {\n                    \"type\": \"string\",\n                    \"title\": \"URL\",\n                    \"description\": \"The URL to the Nightscout API\",\n                    \"default\": \"\"\n                  },\n                  \"http_timeout\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Http request timeout\",\n                    \"description\": \"Milliseconds to use for http request timeouts\",\n                    \"default\": 20\n                  },\n                  \"headers\": {\n                    \"type\": \"object\",\n                    \"title\": \"Headers\",\n                    \"description\": \"A key, value map of Headers to send with the request\",\n                    \"default\": {}\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ramadan\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Ramadan Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/health/ramadan\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"latitude\": {\n                    \"type\": \"number\",\n                    \"title\": \"Latitude\",\n                    \"description\": \"Latitude for prayer time calculation\",\n                    \"default\": 0\n                  },\n                  \"longitude\": {\n                    \"type\": \"number\",\n                    \"title\": \"Longitude\",\n                    \"description\": \"Longitude for prayer time calculation\",\n                    \"default\": 0\n                  },\n                  \"city\": {\n                    \"type\": \"string\",\n                    \"title\": \"City\",\n                    \"description\": \"City name for location lookup (takes precedence over latitude/longitude)\",\n                    \"default\": \"\"\n                  },\n                  \"country\": {\n                    \"type\": \"string\",\n                    \"title\": \"Country\",\n                    \"description\": \"Country name or ISO 3166 alpha-2 code (required when using city)\",\n                    \"default\": \"\"\n                  },\n                  \"method\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Calculation Method\",\n                    \"description\": \"Prayer calculation method ID (0-23). See https://aladhan.com/calculation-methods\",\n                    \"default\": 3\n                  },\n                  \"school\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Madhab School\",\n                    \"description\": \"0 = Shafi (standard), 1 = Hanafi\",\n                    \"default\": 0\n                  },\n                  \"hide_outside_ramadan\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Hide Outside Ramadan\",\n                    \"description\": \"Hide the segment when not in Ramadan\",\n                    \"default\": true\n                  },\n                  \"first_roza_date\": {\n                    \"type\": \"string\",\n                    \"title\": \"First Roza Date\",\n                    \"description\": \"Override first day of Ramadan as YYYY-MM-DD for local moon sighting\",\n                    \"default\": \"\"\n                  },\n                  \"http_timeout\": {\n                    \"type\": \"integer\",\n                    \"title\": \"HTTP request timeout\",\n                    \"description\": \"Milliseconds to use for HTTP request timeouts\",\n                    \"default\": 20\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nba\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"NBA Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/nba\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"team\": {\n                    \"type\": \"string\",\n                    \"title\": \"Team\",\n                    \"description\": \"Tri-code for the NBA team you want to get data for\",\n                    \"default\": \"\"\n                  },\n                  \"days_offset\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Days Offset\",\n                    \"description\": \"How many days in advance you wish to see game information for\",\n                    \"default\": 8\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nim\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Nim Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/nim\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.nim\",\n                      \"*.nims\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"nim\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nix-shell\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Nix Shell\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/nix-shell\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"node\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Node Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/node\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"fetch_package_manager\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Display Package Manager\",\n                    \"description\": \"Assigns the Yarn or NPM icon to .PackageManagerIcon\",\n                    \"default\": false\n                  },\n                  \"pnpm_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"PNPM Icon\",\n                    \"description\": \"Icon/text to use for PNPM\",\n                    \"default\": \"\\ue865\"\n                  },\n                  \"yarn_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Yarn Icon\",\n                    \"description\": \"Icon/text to use for Yarn\",\n                    \"default\": \"\\ue6a7\"\n                  },\n                  \"npm_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"NPM Icon\",\n                    \"description\": \"Icon/text to use for NPM\",\n                    \"default\": \"\\ue71e\"\n                  },\n                  \"bun_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Bun Icon\",\n                    \"description\": \"Icon/text to use for Bun\",\n                    \"default\": \"\\ue76f\"\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.js\",\n                      \"*.ts\",\n                      \"package.json\",\n                      \".nvmrc\",\n                      \"pnpm-workspace.yaml\",\n                      \".pnpmfile.cjs\",\n                      \".vue\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"node\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"npm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"NPM Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/npm\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"package.json\",\n                      \"package-lock.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"npm\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"nx\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Nx Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/nx\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"workspace.json\",\n                      \"nx.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"nx\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ocaml\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"OCaml Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/ocaml\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.ml\",\n                      \"*.mli\",\n                      \"dune\",\n                      \"dune-project\",\n                      \"dune-workspace\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"ocaml\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"os\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Operating System Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/os\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"macos\": {\n                    \"type\": \"string\",\n                    \"title\": \"MacOS Icon\",\n                    \"description\": \"Icon/text to use for macOS\",\n                    \"default\": \"\\uf179\"\n                  },\n                  \"linux\": {\n                    \"type\": \"string\",\n                    \"title\": \"Linux Icon\",\n                    \"description\": \"Icon/text to use for Linux\",\n                    \"default\": \"\\uf17c\"\n                  },\n                  \"windows\": {\n                    \"type\": \"string\",\n                    \"title\": \"Windows Icon\",\n                    \"description\": \"Icon/text to use for Windows\",\n                    \"default\": \"\\ue62a\"\n                  },\n                  \"display_distro_name\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Distro Name\",\n                    \"description\": \"Display the distro name or icon or not\",\n                    \"default\": false\n                  },\n                  \"alma\": {\n                    \"type\": \"string\",\n                    \"title\": \"Alma Icon\",\n                    \"description\": \"The icon to use for Alma\",\n                    \"default\": \"\\uf31d\"\n                  },\n                  \"almalinux\": {\n                    \"type\": \"string\",\n                    \"title\": \"AlmaLinux Icon\",\n                    \"description\": \"The icon to use for AlmaLinux\",\n                    \"default\": \"\\uf31d\"\n                  },\n                  \"almalinux9\": {\n                    \"type\": \"string\",\n                    \"title\": \"AlmaLinux9 Icon\",\n                    \"description\": \"The icon to use for AlmaLinux9\",\n                    \"default\": \"\\uf31d\"\n                  },\n                  \"alpine\": {\n                    \"type\": \"string\",\n                    \"title\": \"Alpine Icon\",\n                    \"description\": \"The icon to use for Alpine\",\n                    \"default\": \"\\uf300\"\n                  },\n                  \"android\": {\n                    \"type\": \"string\",\n                    \"title\": \"Android Icon\",\n                    \"description\": \"The icon to use for Android\",\n                    \"default\": \"\\ue70e\"\n                  },\n                  \"aosc\": {\n                    \"type\": \"string\",\n                    \"title\": \"Aosc Icon\",\n                    \"description\": \"The icon to use for Aosc\",\n                    \"default\": \"\\uf301\"\n                  },\n                  \"arch\": {\n                    \"type\": \"string\",\n                    \"title\": \"Arch Icon\",\n                    \"description\": \"The icon to use for Arch\",\n                    \"default\": \"\\uf303\"\n                  },\n                  \"centos\": {\n                    \"type\": \"string\",\n                    \"title\": \"Centos Icon\",\n                    \"description\": \"The icon to use for Centos\",\n                    \"default\": \"\\uf304\"\n                  },\n                  \"coreos\": {\n                    \"type\": \"string\",\n                    \"title\": \"Coreos Icon\",\n                    \"description\": \"The icon to use for Coreos\",\n                    \"default\": \"\\uf305\"\n                  },\n                  \"debian\": {\n                    \"type\": \"string\",\n                    \"title\": \"Debian Icon\",\n                    \"description\": \"The icon to use for Debian\",\n                    \"default\": \"\\uf306\"\n                  },\n                  \"deepin\": {\n                    \"type\": \"string\",\n                    \"title\": \"Deepin Icon\",\n                    \"description\": \"The icon to use for Deepin\",\n                    \"default\": \"\\uf321\"\n                  },\n                  \"devuan\": {\n                    \"type\": \"string\",\n                    \"title\": \"Devuan Icon\",\n                    \"description\": \"The icon to use for Devuan\",\n                    \"default\": \"\\uf307\"\n                  },\n                  \"elementary\": {\n                    \"type\": \"string\",\n                    \"title\": \"Elementary Icon\",\n                    \"description\": \"The icon to use for Elementary\",\n                    \"default\": \"\\uf309\"\n                  },\n                  \"endeavouros\": {\n                    \"type\": \"string\",\n                    \"title\": \"EndeavourOS Icon\",\n                    \"description\": \"The icon to use for EndeavourOS\",\n                    \"default\": \"\\uf322\"\n                  },\n                  \"fedora\": {\n                    \"type\": \"string\",\n                    \"title\": \"Fedora Icon\",\n                    \"description\": \"The icon to use for Fedora\",\n                    \"default\": \"\\uf30a\"\n                  },\n                  \"freebsd\": {\n                    \"type\": \"string\",\n                    \"title\": \"FreeBSD Icon\",\n                    \"description\": \"The icon to use for FreeBSD\",\n                    \"default\": \"\\udb82\\udce0\"\n                  },\n                  \"gentoo\": {\n                    \"type\": \"string\",\n                    \"title\": \"Gentoo Icon\",\n                    \"description\": \"The icon to use for Gentoo\",\n                    \"default\": \"\\uf30d\"\n                  },\n                  \"kali\": {\n                    \"type\": \"string\",\n                    \"title\": \"Kali Icon\",\n                    \"description\": \"The icon to use for Kali\",\n                    \"default\": \"\\uf327\"\n                  },\n                  \"mageia\": {\n                    \"type\": \"string\",\n                    \"title\": \"Mageia Icon\",\n                    \"description\": \"The icon to use for Mageia\",\n                    \"default\": \"\\uf310\"\n                  },\n                  \"manjaro\": {\n                    \"type\": \"string\",\n                    \"title\": \"Manjaro Icon\",\n                    \"description\": \"The icon to use for Manjaro\",\n                    \"default\": \"\\uf312\"\n                  },\n                  \"mint\": {\n                    \"type\": \"string\",\n                    \"title\": \"Mint Icon\",\n                    \"description\": \"The icon to use for Mint\",\n                    \"default\": \"\\udb82\\udced\"\n                  },\n                  \"neon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Neon Icon\",\n                    \"description\": \"The icon to use for Neon\",\n                    \"default\": \"\\uf331\"\n                  },\n                  \"nixos\": {\n                    \"type\": \"string\",\n                    \"title\": \"Nixos Icon\",\n                    \"description\": \"The icon to use for Nixos\",\n                    \"default\": \"\\uf313\"\n                  },\n                  \"opensuse\": {\n                    \"type\": \"string\",\n                    \"title\": \"Opensuse Icon\",\n                    \"description\": \"The icon to use for Opensuse\",\n                    \"default\": \"\\uf314\"\n                  },\n                  \"opensuse-tumbleweed\": {\n                    \"type\": \"string\",\n                    \"title\": \"OpenSUSE Tumbleweed Icon\",\n                    \"description\": \"The icon to use for OpenSUSE Tumbleweed\",\n                    \"default\": \"\\uf314\"\n                  },\n                  \"raspbian\": {\n                    \"type\": \"string\",\n                    \"title\": \"Raspbian Icon\",\n                    \"description\": \"The icon to use for Raspbian\",\n                    \"default\": \"\\uf315\"\n                  },\n                  \"redhat\": {\n                    \"type\": \"string\",\n                    \"title\": \"Redhat Icon\",\n                    \"description\": \"The icon to use for Redhat\",\n                    \"default\": \"\\uf316\"\n                  },\n                  \"rocky\": {\n                    \"type\": \"string\",\n                    \"title\": \"Rocky Icon\",\n                    \"description\": \"The icon to use for Rocky\",\n                    \"default\": \"\\uf32b\"\n                  },\n                  \"sabayon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Sabayon Icon\",\n                    \"description\": \"The icon to use for Sabayon\",\n                    \"default\": \"\\uf317\"\n                  },\n                  \"slackware\": {\n                    \"type\": \"string\",\n                    \"title\": \"Slackware Icon\",\n                    \"description\": \"The icon to use for Slackware\",\n                    \"default\": \"\\uf319\"\n                  },\n                  \"ubuntu\": {\n                    \"type\": \"string\",\n                    \"title\": \"Ubuntu Icon\",\n                    \"description\": \"The icon to use for Ubuntu\",\n                    \"default\": \"\\uf31b\"\n                  },\n                  \"void\": {\n                    \"type\": \"string\",\n                    \"title\": \"Void Icon\",\n                    \"description\": \"The icon to use for Void\",\n                    \"default\": \"\\uf32e\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"owm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Open Weather Map Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/owm\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"api_key\": {\n                    \"type\": \"string\",\n                    \"title\": \"API key\",\n                    \"description\": \"The API key used for the api call (Required)\",\n                    \"default\": \".\"\n                  },\n                  \"location\": {\n                    \"type\": \"string\",\n                    \"title\": \"location\",\n                    \"description\": \"Location to use for the API call interpreted only if valid coordinates aren't given. Formatted as <City>,<STATE>,<COUNTRY_CODE>. City name, state code and country code divided by comma. Please, refer to ISO 3166 for the state codes or country codes.\",\n                    \"default\": \"De Bilt,NL\"\n                  },\n                  \"units\": {\n                    \"type\": \"string\",\n                    \"title\": \"units\",\n                    \"description\": \"Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit). Default is standard\",\n                    \"default\": \"standard\",\n                    \"enum\": [\n                      \"standard\",\n                      \"metric\",\n                      \"imperial\"\n                    ]\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"path\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Path Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/path\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"folder_separator_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Folder Separator Icon\",\n                    \"description\": \"The symbol to use as a separator between folders\",\n                    \"default\": \"/\"\n                  },\n                  \"folder_separator_template\": {\n                    \"type\": \"string\",\n                    \"title\": \"Folder Separator Template\",\n                    \"description\": \"the path which is split will be separated by this template\",\n                    \"pattern\": \"\"\n                  },\n                  \"home_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Home Icon\",\n                    \"description\": \"The icon to display when at $HOME\",\n                    \"default\": \"~\"\n                  },\n                  \"folder_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Folder Icon\",\n                    \"description\": \"The icon to use as a folder indication\",\n                    \"default\": \"..\"\n                  },\n                  \"windows_registry_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Windows Registry Icon\",\n                    \"description\": \"The icon to display when in the Windows registry\",\n                    \"default\": \"\\uf013\"\n                  },\n                  \"style\": {\n                    \"type\": \"string\",\n                    \"title\": \"The Path Style\",\n                    \"description\": \"How to display the current path\",\n                    \"enum\": [\n                      \"agnoster\",\n                      \"agnoster_full\",\n                      \"agnoster_short\",\n                      \"agnoster_left\",\n                      \"short\",\n                      \"full\",\n                      \"folder\",\n                      \"mixed\",\n                      \"letter\",\n                      \"unique\",\n                      \"powerlevel\",\n                      \"fish\"\n                    ],\n                    \"default\": \"agnoster\"\n                  },\n                  \"mapped_locations\": {\n                    \"type\": \"object\",\n                    \"title\": \"Mapped Locations\",\n                    \"description\": \"Custom glyph/text for specific paths\",\n                    \"default\": {}\n                  },\n                  \"mapped_locations_enabled\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Enable the Mapped Locations feature\",\n                    \"description\": \"Replace known locations in the path with the replacements before applying the style.\",\n                    \"default\": true\n                  },\n                  \"max_depth\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Maximum Depth\",\n                    \"description\": \"Maximum path depth to display without shortening\",\n                    \"default\": 1\n                  },\n                  \"max_width\": {\n                    \"type\": [\n                      \"integer\",\n                      \"string\"\n                    ],\n                    \"title\": \"Maximum Width\",\n                    \"description\": \"Maximum path width to display for powerlevel style\",\n                    \"default\": 0\n                  },\n                  \"mixed_threshold\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Mixed threshold\",\n                    \"description\": \"The maximum length of a path segment that will be displayed when using mixed style.\",\n                    \"default\": 4\n                  },\n                  \"hide_root_location\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Hide the root location\",\n                    \"description\": \"Hides the root location, when using agnoster_short style, if it doesn't fit in the last max_depth folders.\",\n                    \"default\": false\n                  },\n                  \"cycle\": {\n                    \"type\": \"array\",\n                    \"title\": \"Color overrides to use to cycle through and color the path per folder\",\n                    \"items\": {\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"cycle_folder_separator\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Cycle the folder_separator_icon\",\n                    \"description\": \"Colorize the folder_separator_icon as well when using a cycle.\",\n                    \"default\": false\n                  },\n                  \"folder_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"The folder format\",\n                    \"description\": \"Golang string format to apply to the folder name\",\n                    \"pattern\": \"%s\"\n                  },\n                  \"edge_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"The format to use on the start and end folder\",\n                    \"description\": \"Golang string format to apply to the start and end folder\",\n                    \"pattern\": \"%s\"\n                  },\n                  \"left_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"The format to use on first folder of the path\",\n                    \"description\": \"Will default to whatever edge_format is set to\",\n                    \"pattern\": \"%s\"\n                  },\n                  \"right_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"The format to use on the last folder of the path\",\n                    \"description\": \"Will default to whatever edge_format is set to\",\n                    \"pattern\": \"%s\"\n                  },\n                  \"gitdir_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"The format to use on a git root directory\",\n                    \"description\": \"Golang string format to apply to the .git folder\",\n                    \"default\": \"\"\n                  },\n                  \"display_cygpath\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display the Cygwin (Linux) style path\",\n                    \"description\": \"Display the Cygwin (Linux) style path using cygpath -u $PWD.\",\n                    \"default\": false\n                  },\n                  \"display_root\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display the root directory (/) on Unix systems\",\n                    \"description\": \"Display the root directory (/) on Unix systems.\",\n                    \"default\": false\n                  },\n                  \"dir_length\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Directory Length\",\n                    \"description\": \"The length of the directory name to display in fish style.\",\n                    \"default\": 1\n                  },\n                  \"full_length_dirs\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Full Length Dirs\",\n                    \"description\": \"Indicates how many full length directory names should be displayed in fish style.\",\n                    \"default\": 1\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"perl\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Perl Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/perl\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \".perl-version\",\n                      \"*.pl\",\n                      \"*.pm\",\n                      \"*.t\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"perl\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"php\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"PHP Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/php\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.php\",\n                      \"composer.json\",\n                      \"composer.lock\",\n                      \".php-version\",\n                      \"blade.php\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"php\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"plastic\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Plastic SCM Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/plastic\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the local changes or not\",\n                    \"default\": false\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  },\n                  \"branch_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Branch Icon\",\n                    \"description\": \"The icon to use in front of the selector branch name\",\n                    \"default\": \"\\ue0a0 \"\n                  },\n                  \"commit_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Commit Icon\",\n                    \"description\": \"Icon/text to display before the selector changeset\",\n                    \"default\": \"\\uf417\"\n                  },\n                  \"tag_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Tag Icon\",\n                    \"description\": \"Icon/text to display before the seletor label\",\n                    \"default\": \"\\uf412\"\n                  },\n                  \"branch_template\": {\n                    \"$ref\": \"#/definitions/branch_template\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  },\n                  \"mapped_branches\": {\n                    \"$ref\": \"#/definitions/mapped_branches\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"pnpm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"PNPM Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/pnpm\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"package.json\",\n                      \"pnpm-lock.yaml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"pnpm\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"style\": {\n                \"const\": \"powerline\"\n              }\n            }\n          },\n          \"then\": {\n            \"properties\": {\n              \"powerline_symbol\": {\n                \"type\": \"string\",\n                \"title\": \"Powerline Symbol\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/segment#powerline-symbol\",\n                \"default\": \"\\ue0b0\"\n              },\n              \"leading_powerline_symbol\": {\n                \"type\": \"string\",\n                \"title\": \"Leading Powerline Symbol\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/segment#powerline-symbol\",\n                \"default\": \"\\ue0d7\"\n              },\n              \"invert_powerline\": {\n                \"type\": \"boolean\",\n                \"title\": \"Flip the Powerline symbol vertically\",\n                \"description\": \"https://ohmyposh.dev/docs/configuration/segment#invert-powerline\",\n                \"default\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"project\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Project Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/project\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"always_enabled\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Always Enabled\",\n                    \"description\": \"Always show the segment\",\n                    \"default\": false\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"pulumi\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Pulumi Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/pulumi\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_stack\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Stack\",\n                    \"description\": \"Fetch the current pulumi stack or not\",\n                    \"default\": false\n                  },\n                  \"fetch_about\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch About\",\n                    \"description\": \"Fetch the URL and user for the current stack\",\n                    \"default\": false\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"python\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Python Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/python\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"fetch_virtual_env\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Virtual Env\",\n                    \"description\": \"Fetch the name of the virtualenv or not\",\n                    \"default\": true\n                  },\n                  \"display_default\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Default\",\n                    \"description\": \"Show the name of the virtualenv when it's default\",\n                    \"default\": true\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.py\",\n                      \"*.ipynb\",\n                      \"pyproject.toml\",\n                      \"venv.bak\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \".venv\",\n                      \"venv\",\n                      \"virtualenv\",\n                      \"venv-win\",\n                      \"pyenv-win\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"pyenv\",\n                      \"python\",\n                      \"python3\",\n                      \"py\"\n                    ]\n                  },\n                  \"folder_name_fallback\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Folder Name Fallback\",\n                    \"description\": \"Replace virtual environment names in default_venv_names list with parent folder name\",\n                    \"default\": \"true\"\n                  },\n                  \"default_venv_names\": {\n                    \"type\": \"array\",\n                    \"title\": \"Default Venv Names\",\n                    \"description\": \"Names to replace when folder_name_fallback is true\",\n                    \"default\": [\n                      \".venv\",\n                      \"venv\"\n                    ],\n                    \"items\": {\n                      \"type\": \"string\"\n                    }\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"quasar\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Quasar Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/quasar\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"fetch_dependencies\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Dependencies\",\n                    \"description\": \"Fetch the vite and @quasar/app-vite dependency information or not\",\n                    \"default\": false\n                  },\n                  \"extensions\": {\n                    \"default\": [\n                      \"quasar.config\",\n                      \"quasar.config.js\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"quasar\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"r\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"R Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/r\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.R\",\n                      \"*.Rmd\",\n                      \"*.Rsx\",\n                      \"*.Rda\",\n                      \"*.Rd\",\n                      \"*.Rproj\",\n                      \".Rproj.user\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"Rscript\",\n                      \"R\",\n                      \"R.exe\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"react\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"React Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/react\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"package.json\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"react\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"root\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Root Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/root\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ruby\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Ruby Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/ruby\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.rb\",\n                      \"Rakefile\",\n                      \"Gemfile\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"rbenv\",\n                      \"rvm-prompt\",\n                      \"chruby\",\n                      \"asdf\",\n                      \"ruby\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"rust\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Rust Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/rust\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.rs\",\n                      \"Cargo.toml\",\n                      \"Cargo.lock\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"rustc\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"sapling\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Sapling Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/sapling\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the local changes or not\",\n                    \"default\": true\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"session\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Session Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/session\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"shell\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Shell Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/shell\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"mapped_shell_names\": {\n                    \"type\": \"object\",\n                    \"description\": \"Mapping of shell identifiers to the glyph/string used for that shell (e.g. bash, zsh, pwsh).\",\n                    \"additionalProperties\": {\n                      \"type\": \"string\"\n                    },\n                    \"example\": {\n                      \"bash\": \"\\udb84\\udd83\",\n                      \"zsh\": \"\",\n                      \"pwsh\": \"\",\n                      \"shell\": \"$\"\n                    }\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"sitecore\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Sitecore Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cloud/sitecore\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"display_default\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Default\",\n                    \"description\": \"Display the segment or not when the Sitecore environment name matches `default`\",\n                    \"default\": true\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"spotify\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Spotify Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/music/spotify\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"playing_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Playing Icon\",\n                    \"description\": \"Text/icon to show when playing\",\n                    \"default\": \"\\ue602 \"\n                  },\n                  \"paused_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Paused Icon\",\n                    \"description\": \"Text/icon to show when paused\",\n                    \"default\": \"\\uf04c \"\n                  },\n                  \"stopped_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Stopped Icon\",\n                    \"description\": \"Text/icon to show when stopped\",\n                    \"default\": \"\\uf04d \"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"status\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Status Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/status\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"always_enabled\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Always Enabled\",\n                    \"description\": \"Always show the status\",\n                    \"default\": false\n                  },\n                  \"status_template\": {\n                    \"type\": \"string\",\n                    \"title\": \"Status Template\",\n                    \"description\": \"The template to use for the status segment\",\n                    \"default\": \"{{ .Code }}\"\n                  },\n                  \"status_separator\": {\n                    \"type\": \"string\",\n                    \"title\": \"Status Separator\",\n                    \"description\": \"The separator to use between the status segments\",\n                    \"default\": \"|\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"strava\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Display training data from Strava\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/health/strava\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"ride_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Ride icon\",\n                    \"description\": \"Alternative icon for this activity type\",\n                    \"default\": \"\\uf206\"\n                  },\n                  \"run_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Run icon\",\n                    \"description\": \"Alternative icon for this activity type\",\n                    \"default\": \"\\ue213\"\n                  },\n                  \"skiing_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Skiing icon\",\n                    \"description\": \"Alternative icon for this activity type\",\n                    \"default\": \"\\ue213\"\n                  },\n                  \"workout_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Workout icon\",\n                    \"description\": \"Alternative icon for this activity type\",\n                    \"default\": \"\\ue213\"\n                  },\n                  \"unknown_activity_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Fallback icon\",\n                    \"description\": \"Fallback icon for other activity types\",\n                    \"default\": \"\\ue213\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  },\n                  \"access_token\": {\n                    \"$ref\": \"#/definitions/access_token\"\n                  },\n                  \"refresh_token\": {\n                    \"$ref\": \"#/definitions/refresh_token\"\n                  },\n                  \"expires_in\": {\n                    \"$ref\": \"#/definitions/expires_in\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"svelte\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Svelte Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/svelte\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"svelte.config.js\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"svelte\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"svn\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"SVN Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/scm/svn\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"fetch_status\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Display Status\",\n                    \"description\": \"Display the local changes or not\",\n                    \"default\": false\n                  },\n                  \"status_formats\": {\n                    \"$ref\": \"#/definitions/status_formats\"\n                  },\n                  \"native_fallback\": {\n                    \"$ref\": \"#/definitions/native_fallback\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"swift\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Swift Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/swift\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.swift\",\n                      \"*.SWIFT\",\n                      \"Podfile\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"swift\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"sysinfo\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Get sysinfo\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/sysinfo\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"precision\": {\n                    \"type\": \"integer\",\n                    \"title\": \"Precision\",\n                    \"description\": \"number of decimal places to show\",\n                    \"default\": 2\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"talosctl\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Talosctl Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/talosctl\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"tauri\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Tauri Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/tauri\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"tauri.conf.json\"\n                    ]\n                  },\n                  \"folders\": {\n                    \"default\": [\n                      \"src-tauri\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"tauri\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"taskwarrior\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Taskwarrior Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/taskwarrior\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"command\": {\n                    \"type\": \"string\",\n                    \"title\": \"Taskwarrior Command\",\n                    \"description\": \"The taskwarrior command to use\",\n                    \"default\": \"task\"\n                  },\n                  \"commands\": {\n                    \"type\": \"object\",\n                    \"title\": \"Commands\",\n                    \"description\": \"Map of name to Taskwarrior arguments; the trimmed stdout of each invocation is exposed as .Commands.<Name> in the template\",\n                    \"additionalProperties\": {\n                      \"type\": \"string\"\n                    },\n                    \"default\": {\n                      \"due\": \"+PENDING due.before:tomorrow count\",\n                      \"scheduled\": \"+PENDING scheduled.before:tomorrow count\",\n                      \"waiting\": \"+WAITING count\",\n                      \"context\": \"_get rc.context\"\n                    }\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"terraform\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Terraform Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/terraform\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"command\": {\n                    \"type\": \"string\",\n                    \"title\": \"Terraform Command\",\n                    \"description\": \"The terraform command to use\",\n                    \"default\": \"terraform\"\n                  },\n                  \"fetch_version\": {\n                    \"type\": \"boolean\",\n                    \"title\": \"Fetch Version\",\n                    \"description\": \"Fetch the version number\",\n                    \"default\": false\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"text\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Text Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/text\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"time\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Time Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/time\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"time_format\": {\n                    \"type\": \"string\",\n                    \"title\": \"Time Format\",\n                    \"description\": \"Format to use, follows the golang standard: https://gobyexample.com/time-formatting-parsing\",\n                    \"default\": \"15:04:05\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"todoist\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Todoist Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/todoist\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"api_key\": {\n                    \"type\": \"string\",\n                    \"title\": \"API Key\",\n                    \"description\": \"API Key (Required)\",\n                    \"default\": \".\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ui5tooling\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"UI5 tooling CLI segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/ui5tooling\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*ui5*.y*ml\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"ui5\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"umbraco\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Umbraco Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/umbraco\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"unity\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Unity Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/unity\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"upgrade\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Upgrade Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/upgrade\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"cache_duration\": {\n                    \"$ref\": \"#/definitions/cache_duration\",\n                    \"default\": \"168h\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"v\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"V Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/v\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.v\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"v\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"vala\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Vala Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/vala\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.vala\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"vala\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"wakatime\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Wakatime\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/web/wakatime\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"url\": {\n                    \"type\": \"string\",\n                    \"title\": \"URL\",\n                    \"description\": \"The url used for the api call (Required)\",\n                    \"default\": \".\"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"winget\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"WinGet\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/winget\"\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"winreg\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Windows Registry Query\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/system/winreg\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"path\": {\n                    \"type\": \"string\",\n                    \"title\": \"Registry Path\",\n                    \"description\": \"The path to the registry key (case insensitive, must use backslashes).  Ending with \\\\ will retrieve \\\"(Default)\\\" key in that path.\",\n                    \"default\": \"\"\n                  },\n                  \"fallback\": {\n                    \"type\": \"string\",\n                    \"title\": \"Fallback value\",\n                    \"description\": \"Value to display if registry value cannot be retrieved\",\n                    \"default\": \"\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"withings\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Display activity data from Withings\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/health/withings\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  },\n                  \"access_token\": {\n                    \"$ref\": \"#/definitions/access_token\"\n                  },\n                  \"refresh_token\": {\n                    \"$ref\": \"#/definitions/refresh_token\"\n                  },\n                  \"expires_in\": {\n                    \"$ref\": \"#/definitions/expires_in\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"xmake\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"XMake Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/xmake\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"xmake.lua\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"xmake\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"yarn\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Yarn Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/cli/yarn\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"package.json\",\n                      \"yarn.lock\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"yarn\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"ytm\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"YouTube Music Desktop App Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/music/ytm\",\n            \"properties\": {\n              \"options\": {\n                \"properties\": {\n                  \"playing_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Playing Icon\",\n                    \"description\": \"Text/icon to show when playing\",\n                    \"default\": \"\\uf04b \"\n                  },\n                  \"paused_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Paused Icon\",\n                    \"description\": \"Text/icon to show when paused\",\n                    \"default\": \"\\uf04c \"\n                  },\n                  \"stopped_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Stopped Icon\",\n                    \"description\": \"Text/icon to show when stopped\",\n                    \"default\": \"\\uf04d \"\n                  },\n                  \"ad_icon\": {\n                    \"type\": \"string\",\n                    \"title\": \"Advertisement Icon\",\n                    \"description\": \"Text/icon to show when an advertisement is playing\",\n                    \"default\": \"\\ueebb \"\n                  },\n                  \"http_timeout\": {\n                    \"$ref\": \"#/definitions/http_timeout\"\n                  }\n                },\n                \"unevaluatedProperties\": false\n              }\n            }\n          }\n        },\n        {\n          \"if\": {\n            \"properties\": {\n              \"type\": {\n                \"const\": \"zig\"\n              }\n            }\n          },\n          \"then\": {\n            \"title\": \"Zig Segment\",\n            \"description\": \"https://ohmyposh.dev/docs/segments/languages/zig\",\n            \"properties\": {\n              \"options\": {\n                \"allOf\": [\n                  {\n                    \"$ref\": \"#/definitions/language_options\"\n                  }\n                ],\n                \"properties\": {\n                  \"extensions\": {\n                    \"default\": [\n                      \"*.zig\",\n                      \"*.zon\"\n                    ]\n                  },\n                  \"tooling\": {\n                    \"default\": [\n                      \"zig\"\n                    ]\n                  }\n                }\n              }\n            }\n          }\n        }\n      ]\n    }\n  },\n  \"required\": [\n    \"blocks\"\n  ],\n  \"properties\": {\n    \"final_space\": {\n      \"type\": \"boolean\",\n      \"title\": \"Final Space\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#general-settings\",\n      \"default\": true\n    },\n    \"enable_cursor_positioning\": {\n      \"type\": \"boolean\",\n      \"title\": \"Enable Cursor Positioning\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#general-settings\",\n      \"default\": false\n    },\n    \"shell_integration\": {\n      \"type\": \"boolean\",\n      \"title\": \"FTCS command marks for shell integration\",\n      \"default\": false\n    },\n    \"pwd\": {\n      \"type\": \"string\",\n      \"title\": \"Enable OSC99/7/51\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#general-settings\",\n      \"default\": \"\"\n    },\n    \"upgrade\": {\n      \"type\": \"object\",\n      \"title\": \"Enable Upgrade Notice\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#general-settings\",\n      \"default\": {\n        \"source\": \"cdn\",\n        \"auto\": false,\n        \"notice\": false\n      },\n      \"properties\": {\n        \"interval\": {\n          \"$ref\": \"#/definitions/cache_duration\"\n        },\n        \"source\": {\n          \"type\": \"string\",\n          \"enum\": [\n            \"cdn\",\n            \"github\"\n          ],\n          \"default\": \"cdn\"\n        },\n        \"auto\": {\n          \"type\": \"boolean\",\n          \"default\": false\n        },\n        \"notice\": {\n          \"type\": \"boolean\",\n          \"default\": false\n        }\n      }\n    },\n    \"patch_pwsh_bleed\": {\n      \"type\": \"boolean\",\n      \"title\": \"Patch PowerShell Color Bleed\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#general-settings\",\n      \"default\": false\n    },\n    \"console_title_template\": {\n      \"type\": \"string\",\n      \"title\": \"Console Title Template\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/title#console-title-template\",\n      \"default\": \"{{ .Shell }} in {{ .Folder }}\"\n    },\n    \"terminal_background\": {\n      \"$ref\": \"#/definitions/color\"\n    },\n    \"streaming\": {\n      \"type\": \"integer\",\n      \"title\": \"Streaming Mode\",\n      \"description\": \"https://ohmyposh.dev/docs/experimental/streaming\",\n      \"default\": 100\n    },\n    \"blocks\": {\n      \"type\": \"array\",\n      \"title\": \"Block array\",\n      \"default\": [],\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#blocks\",\n      \"items\": {\n        \"$ref\": \"#/definitions/block\"\n      }\n    },\n    \"tooltips\": {\n      \"type\": \"array\",\n      \"title\": \"Tooltip list, prompt elements to display based on context\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/tooltips\",\n      \"default\": [],\n      \"items\": {\n        \"allOf\": [\n          {\n            \"$ref\": \"#/definitions/segment\"\n          }\n        ],\n        \"properties\": {\n          \"tips\": {\n            \"type\": \"array\",\n            \"title\": \"The commands for which you want the segment to show\",\n            \"items\": {\n              \"type\": \"string\"\n            }\n          }\n        },\n        \"required\": [\n          \"tips\"\n        ]\n      }\n    },\n    \"transient_prompt\": {\n      \"$ref\": \"#/definitions/extra_prompt\",\n      \"title\": \"Transient Prompt Setting\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/transient\",\n      \"anyOf\": [\n        {\n          \"properties\": {\n            \"filler\": {\n              \"$ref\": \"#/definitions/filler\"\n            },\n            \"newline\": {\n              \"type\": \"boolean\",\n              \"title\": \"Newline\",\n              \"description\": \"Add a newline before the prompt\",\n              \"default\": false\n            }\n          }\n        }\n      ]\n    },\n    \"valid_line\": {\n      \"$ref\": \"#/definitions/extra_prompt\",\n      \"title\": \"Valid Line Setting (for PowerShell only)\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/line-error\"\n    },\n    \"error_line\": {\n      \"$ref\": \"#/definitions/extra_prompt\",\n      \"title\": \"Error Line Setting (for PowerShell only)\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/line-error\"\n    },\n    \"secondary_prompt\": {\n      \"$ref\": \"#/definitions/extra_prompt\",\n      \"title\": \"Secondary Prompt Setting\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/secondary-prompt\"\n    },\n    \"debug_prompt\": {\n      \"$ref\": \"#/definitions/extra_prompt\",\n      \"title\": \"Debug Prompt Setting (for PowerShell only)\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/debug-prompt\"\n    },\n    \"palette\": {\n      \"type\": \"object\",\n      \"title\": \"Palette\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/colors#palette\",\n      \"default\": {},\n      \"patternProperties\": {\n        \".*\": {\n          \"$ref\": \"#/definitions/color\"\n        }\n      }\n    },\n    \"palettes\": {\n      \"type\": \"object\",\n      \"title\": \"Palettes\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/colors#palettes\",\n      \"default\": {},\n      \"properties\": {\n        \"template\": {\n          \"type\": \"string\",\n          \"title\": \"Prompt Template\"\n        },\n        \"list\": {\n          \"type\": \"object\",\n          \"title\": \"List of palettes\",\n          \"patternProperties\": {\n            \".*\": {\n              \"$ref\": \"#/properties/palette\"\n            }\n          }\n        }\n      }\n    },\n    \"cycle\": {\n      \"type\": \"array\",\n      \"title\": \"List of settings to cycle through segment by segment\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/colors#cycle\",\n      \"default\": [],\n      \"items\": {\n        \"properties\": {\n          \"foreground\": {\n            \"$ref\": \"#/definitions/color\"\n          },\n          \"background\": {\n            \"$ref\": \"#/definitions/color\"\n          }\n        }\n      }\n    },\n    \"accent_color\": {\n      \"title\": \"Accent color\",\n      \"$ref\": \"#/definitions/color\"\n    },\n    \"iterm_features\": {\n      \"type\": \"array\",\n      \"title\": \"The iTerm2 features to enable\",\n      \"items\": {\n        \"type\": \"string\",\n        \"enum\": [\n          \"prompt_mark\",\n          \"current_dir\",\n          \"remote_host\"\n        ]\n      }\n    },\n    \"var\": {\n      \"type\": \"object\",\n      \"title\": \"Config variables to use in templates (can be any value)\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/templates#config-variables\",\n      \"default\": {}\n    },\n    \"maps\": {\n      \"type\": \"object\",\n      \"title\": \"Custom text mappings\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#maps\",\n      \"default\": {},\n      \"items\": {\n        \"properties\": {\n          \"user_name\": {\n            \"$ref\": \"#/definitions/aliases\"\n          },\n          \"host_name\": {\n            \"$ref\": \"#/definitions/aliases\"\n          },\n          \"shell_name\": {\n            \"$ref\": \"#/definitions/aliases\"\n          }\n        }\n      }\n    },\n    \"async\": {\n      \"type\": \"boolean\",\n      \"title\": \"Async loading\",\n      \"default\": false\n    },\n    \"tooltips_action\": {\n      \"type\": \"string\",\n      \"title\": \"Tooltips action\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/tooltips#tooltips-action\",\n      \"enum\": [\n        \"replace\",\n        \"extend\",\n        \"prepend\"\n      ],\n      \"default\": \"replace\"\n    },\n    \"version\": {\n      \"type\": \"integer\",\n      \"title\": \"Version\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general\",\n      \"default\": 4\n    },\n    \"extends\": {\n      \"type\": \"string\",\n      \"title\": \"Extends\",\n      \"description\": \"https://ohmyposh.dev/docs/configuration/general#extends\",\n      \"default\": \"\"\n    }\n  }\n}\n"
  },
  {
    "path": "themes/sim-web.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"right\",\n      \"overflow\": \"hide\",\n      \"segments\": [\n        {\n          \"type\": \"executiontime\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#a9ffb4\",\n          \"template\": \" {{ .FormattedMs }}s <#ffffff>\\ue601</>\",\n          \"options\": {\n            \"threshold\": 0,\n            \"style\": \"dallas\"\n          }\n        },\n        {\n          \"type\": \"node\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#45bf17\",\n          \"template\": \" \\ue718 {{ .Full }} \"\n        },\n        {\n          \"type\": \"npm\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#FE4A49\",\n          \"template\": \"<#F3EFF5>and</> \\ue71e {{ .Full }} \"\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"overflow\": \"break\",\n      \"segments\": [\n        {\n          \"type\": \"path\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#ffafd2\",\n          \"options\": {\n            \"style\": \"agnoster_full\",\n            \"home_icon\": \"home\",\n            \"folder_icon\": \"\\uf07b\",\n            \"folder_separator_icon\": \" \\u276f \"\n          },\n          \"template\": \"\\ue5ff {{ .Path }} \"\n        },\n        {\n          \"type\": \"git\",\n          \"style\": \"powerline\",\n          \"foreground\": \"#f14e32\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \"\n          },\n          \"template\": \"({{ .HEAD }})\"\n        }\n      ]\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"type\": \"prompt\",\n      \"segments\": [\n        {\n          \"type\": \"status\",\n          \"style\": \"diamond\",\n          \"foreground\": \"#00c7fc\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"template\": \"<#00c7fc>\\u276f</>_: \"\n        }\n      ]\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"{{ .Shell }}\"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/slim.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#26C6DA\",\n          \"leading_diamond\": \"\\ue0c7\\u2593\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}\\ue712 on {{ end }}{{ .Icon }}<#7a7a7a> \\ue0b1</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if ne .Env.POSH_SESSION_DEFAULT_USER .UserName }}<#77f5d6>{{ .UserName }}</><#7a7a7a>\\uf1fa</>{{ end }}<#2EEFBF>{{ .HostName }}</><#7a7a7a> \\ue0b1</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffff66\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7<#7a7a7a> \\ue0b1</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"options\": {\n            \"folder_icon\": \"<#B5B2C2>\\ue5fe </>\",\n            \"folder_separator_icon\": \"<#B5B2C2>\\ue0bf </>\",\n            \"home_icon\": \"\\uf015\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#f2f200> \\ue5ff </>{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffeb3b\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb3b{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#2EC4B6{{ end }}\",\n            \"{{ if gt .Behind 0 }}#8A4FFF{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#7a7a7a>\\ue0b1 </>{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<#E84855> \\uf044 {{ .Working.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#2FDA4E> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#6CA35E\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#96E072\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#3891A6\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue77f {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }}<#007ACC> \\ue641 </>\",\n          \"trailing_diamond\": \"\\u2593\\ue0c6\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#7a7a7a\",\n          \"style\": \"plain\",\n          \"template\": \"~#@\\u276f\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7a7a7a\",\n          \"style\": \"plain\",\n          \"template\": \" \\u276e \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#FFCE5C\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 500\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }}<#fafafa> \\uf252 </>\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"foreground\": \"#9FD356\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#E84855{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\uea9f {{ if gt .Code 0 }}{{ .Code }}{{ end }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}root :: {{end}}{{.Shell}} :: {{.Folder}}\",\n  \"final_space\": true,\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#7a7a7a\",\n    \"template\": \" ~#@\\u276f \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/slimfat.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#26C6DA\",\n          \"leading_diamond\": \"\\ue0c7\\u2593\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue70f\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}\\ue712 on {{ end }}{{ .Icon }}<#7a7a7a> \\ue0b1</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if ne .Env.POSH_SESSION_DEFAULT_USER .UserName }}<#77f5d6>{{ .UserName }}</><#7a7a7a>\\uf1fa</>{{ end }}<#2EEFBF>{{ .HostName }}</><#7a7a7a> \\ue0b1</>\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffff66\",\n          \"style\": \"diamond\",\n          \"template\": \" \\uf0e7<#7a7a7a> \\ue0b1</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"options\": {\n            \"folder_icon\": \"<#B5B2C2>\\ue5fe </>\",\n            \"style\": \"full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#f2f200> \\ue5ff </>{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#ffeb3b\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb3b{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#2EC4B6{{ end }}\",\n            \"{{ if gt .Behind 0 }}#8A4FFF{{ end }}\"\n          ],\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#7a7a7a>\\ue0b1 </>{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }}<#E84855> \\uf044 {{ .Working.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#2FDA4E> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"style\": \"diamond\",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"type\": \"text\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#6CA35E\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#96E072\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#3891A6\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue77f {{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }}<#7a7a7a> \\ue0b3</>\",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#2f2f2f\",\n          \"foreground\": \"#fafafa\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }}<#007ACC> \\ue641 </>\",\n          \"trailing_diamond\": \"\\u2593\\ue0c6\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#7a7a7a\",\n          \"style\": \"plain\",\n          \"template\": \" ~#@\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7a7a7a\",\n          \"style\": \"plain\",\n          \"template\": \" \\u276e \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#FFCE5C\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 500\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }}<#fafafa> \\uf252 </>\",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"foreground\": \"#9FD356\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#E84855{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\uea9f {{ if gt .Code 0 }}{{ .Code }}{{ end }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"console_title_template\": \"{{if .Root}}root :: {{end}}{{.Shell}} :: {{.Folder}}\",\n  \"final_space\": true,\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#7a7a7a\",\n    \"template\": \" ~#@\\u276f \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/smoothie.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#b1ff4f\",\n          \"style\": \"powerline\",\n          \"template\": \"[🐍 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}] \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#ffaed8\",\n          \"options\": {\n            \"folder_separator_icon\": \" | \",\n            \"home_icon\": \"\\uf46d\",\n            \"style\": \"letter\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#eaeaea>\\u23a7</> \\u27e8{{ .Path }}\\u27e9 \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#62beff\",\n          \"options\": {\n            \"branch_icon\": \"\\uf418\",\n            \"branch_identical_icon\": \"\\u2261\",\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u27e8{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\u2206{{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}\\u27e9\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#98C379\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>\\u25e6</> \\u2622{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#fb0207\",\n          \"style\": \"plain\",\n          \"template\": \" ××× \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#9966ff\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 0\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u27e8{{ .FormattedMs }}\\u27e9 <#eaeaea>\\u23ab</>\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#3ce6bf\",\n          \"style\": \"plain\",\n          \"template\": \"<#eaeaea>\\u23a9</>\\u27e9\\u27e9\\u27e9\\u27e9\\u27e9\\u27e9 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#f5f5a6\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u27e8{{ .CurrentDate | date .Format }}\\u27e9 <#eaeaea>\\u23ad</>\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/sonicboom_dark.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#dd1e1e\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"folder_icon\": \"\\ue5fe\",\n            \"folder_separator_icon\": \" <#000000>\\ue0bd </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#00ff0d\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .FormattedMs }}s \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \"\\ue0c5\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}<transparent> / </>{{ .HostName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#272727\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"time_format\": \"3:04:05 PM\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000> \\ue31e\\uf0fb </>{{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0c5\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#00ff0d\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\uf432 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/sonicboom_light.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#dd1e1e\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#000000\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"alpine\": \"\\uf300\",\n            \"arch\": \"\\uf303\",\n            \"centos\": \"\\uf304\",\n            \"debian\": \"\\uf306\",\n            \"elementary\": \"\\uf309\",\n            \"fedora\": \"\\uf30a\",\n            \"gentoo\": \"\\uf30d\",\n            \"linux\": \"\\ue712\",\n            \"macos\": \"\\ue711\",\n            \"manjaro\": \"\\uf312\",\n            \"mint\": \"\\uf30f\",\n            \"opensuse\": \"\\uf314\",\n            \"raspbian\": \"\\uf315\",\n            \"ubuntu\": \"\\uf31c\",\n            \"windows\": \"\\ue62a\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#4d4d4d\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"folder_icon\": \"\\ue5fe\",\n            \"folder_separator_icon\": \"<transparent> \\ue0bd </>\",\n            \"home_icon\": \"\\ueb06\",\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#4d4d4d\",\n          \"foreground\": \"#00ff0d\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .HEAD }}{{ if .Staging.Changed }}<#FF6F00> \\uf046 {{ .Staging.String }}</>{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#4d4d4d\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000>\\ue0b1 </>{{ .FormattedMs }}s \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#4d4d4d\",\n          \"foreground\": \"#43CCEA\",\n          \"leading_diamond\": \"\\ue0c5\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}<transparent> / </>{{ .HostName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#4d4d4d\",\n          \"foreground\": \"#43CCEA\",\n          \"options\": {\n            \"time_format\": \"3:04:05 PM\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<#000000> \\ue31e\\uf0fb </>{{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0c5\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#00ff0d\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ff0000{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\uf432 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/sorin.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#CB4B16\",\n          \"style\": \"plain\",\n          \"template\": \" {{ reason .Code }} \",\n          \"type\": \"status\"\n        },\n        {\n          \"foreground\": \"#CECE04\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#FFFFFF\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#0973C0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#C1C106\",\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>git:</>{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#100e23\",\n          \"style\": \"plain\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"<#CB4B16>\\u276f</><#CACA02>\\u276f</><#4E9A06>\\u276f</> \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/space.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#26C6DA\",\n          \"options\": {\n            \"macos\": \"mac\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"#26C6DA\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .UserName }}: \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"lightGreen\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on</> {{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#906cff\",\n          \"style\": \"powerline\",\n          \"template\": \"[\\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}] \",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"#7FD5EA\",\n          \"style\": \"powerline\",\n          \"template\": \"[\\ue626 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}] \",\n          \"type\": \"go\"\n        },\n        {\n          \"foreground\": \"#76b367\",\n          \"style\": \"powerline\",\n          \"template\": \"[\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}] \",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#f44336\",\n          \"style\": \"powerline\",\n          \"template\": \"[\\ue791{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}] \",\n          \"type\": \"ruby\"\n        },\n        {\n          \"foreground\": \"#ea2d2e\",\n          \"style\": \"powerline\",\n          \"template\": \"[\\ue738 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}] \",\n          \"type\": \"java\"\n        },\n        {\n          \"foreground\": \"#4063D8\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue624 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n          \"type\": \"julia\"\n        },\n        {\n          \"foreground\": \"#FFD54F\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/spaceship.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"lightYellow\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"cyan\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>in</> {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#ff94df\",\n          \"options\": {\n            \"branch_icon\": \" <#ff94df><b>\\ue0a0 </b></>\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on</> {{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightGreen\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/star.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#E06C75\",\n          \"style\": \"plain\",\n          \"template\": \"root <#ffffff>in</> \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#55B9C4\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#C678DD\",\n          \"options\": {\n            \"fetch_status\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>on</> {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#98C379\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#ffffff>via</> \\ue781 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#C94A16\",\n          \"style\": \"plain\",\n          \"template\": \"x \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#63F08C\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/stelbent-compact.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"console_title_template\": \"{{if .Segments.Git.RepoName}} {{.Segments.Git.RepoName}} {{else}} {{.Folder}} {{end}}\",\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"type\": \"session\",\n          \"foreground\": \"#757575\",\n          \"style\": \"plain\",\n          \"template\": \"\\u250c {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }} \"\n        },\n        {\n          \"type\": \"path\",\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"agnoster_full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \"\n        },\n        {\n          \"type\": \"git\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"foreground\": \"#100e23\",\n          \"background\": \"#95ffa4\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#c5b6ad{{ end }}\"\n          ],\n          \"template\": \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} \\u2502{{ end }}{{ if .Staging.Changed }} {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} {{ .StashCount }}{{ end }} \",\n          \"options\": {\n            \"branch_ahead_icon\": \"\\u2191\",\n            \"branch_behind_icon\": \"\\u2193\",\n            \"branch_gone_icon\": \"\\u2262\",\n            \"branch_icon\": \"\\ue0a0 \",\n            \"branch_identical_icon\": \"\\u2261\",\n            \"cherry_pick_icon\": \"\\u2713 \",\n            \"commit_icon\": \"\\u25b7 \",\n            \"fetch_status\": true,\n            \"merge_icon\": \"\\u25f4 \",\n            \"no_commits_icon\": \"[no commits]\",\n            \"rebase_icon\": \"\\u2c62 \",\n            \"tag_icon\": \"\\u25b6 \",\n            \"untracked_modes\": {\n              \"/Users/user/Projects/oh-my-posh/\": \"no\"\n            }\n          }\n        },\n        {\n          \"type\": \"terraform\",\n          \"background\": \"#ffee58\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .WorkspaceName }}{{ if .Version }} {{ .Version }}{{ end }} \"\n        },\n        {\n          \"type\": \"status\",\n          \"background\": \"#ff8080\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ if gt .Code 0 }}error{{ else }}\\uf42e{{ end }} \"\n        },\n        {\n          \"type\": \"time\",\n          \"foreground\": \"#689f38\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" <#757575,>|</> {{ .CurrentDate | date .Format }}\"\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"type\": \"text\",\n          \"foreground\": \"#757575\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2514\"\n        },\n        {\n          \"type\": \"text\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"$\"\n        }\n      ]\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/stelbent.minimal.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#007acc\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .Name }}\",\n          \"type\": \"shell\"\n        },\n        {\n          \"foreground\": \"#ff8080\",\n          \"style\": \"plain\",\n          \"template\": \" <#757575,>as</> root\",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#689f38\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" <#757575,>|</> {{ .CurrentDate | date .Format }}\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#757575\",\n          \"style\": \"plain\",\n          \"template\": \"\\u250c {{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#91ddff\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#95ffa4\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#c5b6ad{{ end }}\"\n          ],\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_ahead_icon\": \"\\u2191\",\n            \"branch_behind_icon\": \"\\u2193\",\n            \"branch_gone_icon\": \"\\u2262\",\n            \"branch_icon\": \"\\ue0a0 \",\n            \"branch_identical_icon\": \"\\u2261\",\n            \"cherry_pick_icon\": \"\\u2713 \",\n            \"commit_icon\": \"\\u25b7 \",\n            \"fetch_status\": true,\n            \"merge_icon\": \"\\u25f4 \",\n            \"no_commits_icon\": \"[no commits]\",\n            \"rebase_icon\": \"\\u2c62 \",\n            \"tag_icon\": \"\\u25b6 \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} \\u2502{{ end }}{{ if .Staging.Changed }} {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#ffee58\",\n          \"foreground\": \"#100e23\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" {{ .WorkspaceName }} \",\n          \"type\": \"terraform\"\n        },\n        {\n          \"background\": \"#ff8080\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" error \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#757575\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2514 \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"$\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/takuya.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#0077c2\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\u256d\\u2500\\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" {{ .Name }} \",\n          \"type\": \"shell\"\n        },\n        {\n          \"background\": \"#ef5350\",\n          \"foreground\": \"#FFFB38\",\n          \"options\": {\n            \"root_icon\": \"\\uf292\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"<parentBackground>\\ue0b0</> \\uf0e7 \",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#444444\",\n          \"foreground\": \"#E4E4E4\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#FFFB38\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ffeb95{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#c5e478{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#C792EA{{ end }}\",\n            \"{{ if gt .Behind 0 }}#C792EA{{ end }}\"\n          ],\n          \"foreground\": \"#011627\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .HEAD }} {{ if .Working.Changed }}{{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }}<#ef5350> \\uf046 {{ .Staging.String }}</>{{ end }} \",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#303030\",\n          \"foreground\": \"#3C873A\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \" <#cc3a3a>\\ue5fa</> \",\n            \"yarn_icon\": \" <#348cba>\\ue6a7</>\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#40c4ff\",\n          \"foreground\": \"#ffffff\",\n          \"invert_powerline\": true,\n          \"leading_diamond\": \" \\ue0b6\",\n          \"style\": \"diamond\",\n          \"template\": \" \\ue641 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#21c7c7\",\n          \"style\": \"plain\",\n          \"template\": \"\\u2570\\u2500\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#e0f8ff\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#ef5350{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/the-unnamed.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#15C2CB\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#F141A8\",\n          \"options\": {\n            \"branch_icon\": \"\\ue0a0 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#F3EFF5>on</> {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#5EADF2\",\n          \"style\": \"plain\",\n          \"template\": \"{{if .Version}}<#F3EFF5>is</> \\uf487 {{.Version}} {{end}}\",\n          \"type\": \"project\"\n        },\n        {\n          \"foreground\": \"#44FFD2\",\n          \"options\": {\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#F3EFF5>via</> \\ue718 {{ .Full }} \",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#FE4A49\",\n          \"style\": \"plain\",\n          \"template\": \"<#F3EFF5>and</> \\ue71e {{.Full}} \",\n          \"type\": \"npm\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#FFE45E\",\n          \"style\": \"plain\",\n          \"template\": \"\\u276f \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/thecyberden.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"diamond\",\n          \"template\": \"{{ if .SSHSession }}\\ueba9{{ else }}\\uf108{{ end }} {{ .UserName }}@{{ .HostName }}\",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#0080ff\",\n          \"foreground\": \"#ffffff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#c19c00\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFA300{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#FF7070{{ end }}\",\n            \"{{ if gt .Behind 0 }}#90F090{{ end }}\"\n          ],\n          \"foreground\": \"#000000\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#2e9599\",\n          \"background_templates\": [\n            \"{{ if gt .Code 0 }}#f1184c{{ end }}\"\n          ],\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \"  \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#2e9599\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ff0000\",\n          \"style\": \"plain\",\n          \"template\": \"\\ue00a \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .Name }} \",\n          \"type\": \"shell\"\n        },\n        {\n          \"foreground\": \"#ffffff\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf054 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/tiwahu.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#007ACC\",\n          \"foreground\": \"#222222\",\n          \"options\": {\n            \"style\": \"austin\",\n            \"threshold\": 321\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#880000\",\n          \"foreground\": \"#ff8888\",\n          \"style\": \"plain\",\n          \"template\": \"{{ if gt .Code 0 }} {{ .Code }} {{ end }}\",\n          \"type\": \"status\"\n        },\n        {\n          \"background\": \"#ffcc88\",\n          \"foreground\": \"#222222\",\n          \"style\": \"plain\",\n          \"template\": \"\\uf0e7\",\n          \"type\": \"root\"\n        },\n        {\n          \"background\": \"#222222\",\n          \"foreground\": \"#666666\",\n          \"style\": \"plain\",\n          \"template\": \" {{ if .WSL }}\\uebcc {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#222222\",\n          \"foreground\": \"#666666\",\n          \"style\": \"plain\",\n          \"template\": \" {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"background\": \"#444444\",\n          \"foreground\": \"#cccccc\",\n          \"options\": {\n            \"folder_icon\": \"\\u2026\",\n            \"style\": \"mixed\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#cf432B\",\n          \"foreground\": \"#f1f0e9\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"cherry_pick_icon\": \"\\ue29b \",\n            \"commit_icon\": \"\\uf417 \",\n            \"fetch_status\": false,\n            \"fetch_upstream_icon\": false,\n            \"merge_icon\": \"\\ue727 \",\n            \"no_commits_icon\": \"\\uf0c3 \",\n            \"rebase_icon\": \"\\ue728 \",\n            \"revert_icon\": \"\\uf0e2 \",\n            \"tag_icon\": \"\\uf412 \"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#7014eb\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue77f \",\n          \"type\": \"dotnet\"\n        },\n        {\n          \"background\": \"#7FD5EA\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue626 \",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#906cff\",\n          \"foreground\": \"#100e23\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue235 \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#99908a\",\n          \"foreground\": \"#193549\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ue7a8 \",\n          \"type\": \"rust\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#007ACC\",\n          \"style\": \"plain\",\n          \"template\": \"{{ .Name }} \",\n          \"type\": \"shell\",\n          \"options\": {\n            \"mapped_shell_names\": {\n              \"pwsh\": \"\\u276f\",\n              \"shell\": \"\\u276f\",\n              \"cmd\": \">\",\n              \"lua\": \">\",\n              \"nu\": \":)\",\n              \"fish\": \"~>\",\n              \"zsh\": \"%\",\n              \"bash\": \"$\"\n            }\n          }\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/tokyo.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"leading_diamond\": \"<#7eb8da>\\u250f</>\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7eb8da\",\n          \"options\": {\n            \"time_format\": \"01/02/2006 @ 3:04:05 PM MST\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uf073</> {{ .CurrentDate | date .Format }}]\",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"#7eb8da\",\n          \"style\": \"plain\",\n          \"template\": \"[<#ffffff>\\ueb99</> {{ .UserName }} :: <#ffffff>\\uf108</> {{ .HostName }}]\",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#be9ddf\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\ue266</> RAM: {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB]\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"foreground\": \"#f36943\",\n          \"foreground_templates\": [\n            \"{{if eq \\\"Charging\\\" .State.String}}#40c4ff{{end}}\",\n            \"{{if eq \\\"Discharging\\\" .State.String}}#ff5722{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}#4caf50{{end}}\"\n          ],\n          \"options\": {\n            \"charged_icon\": \"<#ffffff>\\ue22f</> \",\n            \"charging_icon\": \"\\ueb2d \",\n            \"discharging_icon\": \"<#ffff00>\\uf244</> \"\n          },\n          \"style\": \"plain\",\n          \"template\": \"[{{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\\uf295]\",\n          \"type\": \"battery\"\n        },\n        {\n          \"foreground\": \"#be9ddf\",\n          \"options\": {\n            \"style\": \"dallas\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uf252</> {{ .FormattedMs }}s]\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"leading_diamond\": \"<#7eb8da>\\u2523</>\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7eb8da\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uebd8</> Subscription: <#ffff00>{{ .Name }}</>]\",\n          \"type\": \"az\"\n        },\n        {\n          \"foreground\": \"#7eb8da\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uebd8</> Azure Developer CLI Environment: <#ffff00>{{ .DefaultEnvironment  }}</> :: <#ffff00>{{ .Version }}</>]\",\n          \"type\": \"azd\"\n        },\n        {\n          \"foreground\": \"#7eb8da\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uf270</> <#ffff00>{{ .Profile }}</>{{if .Region}}@<#ffff00>{{ .Region }}</>{{ end }}]\",\n          \"type\": \"aws\"\n        },\n        {\n          \"foreground\": \"#7eb8da\",\n          \"style\": \"diamond\",\n          \"template\": \"[{{ if .Error }}{{ .Error }}{{ else }}<#ffffff>\\uf1a0</> <#ffff00>{{ .Project }}</> :: <#ffff00>{{.Account}}</>{{ end }}]\",\n          \"type\": \"gcp\"\n        },\n        {\n          \"foreground\": \"#ffa5d8\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\udb84\\udcfe</> <#ffff00>{{.Context}}</>{{if .Namespace}} :: <#ffff00>{{.Namespace}}</>{{end}}]\",\n          \"type\": \"kubectl\"\n        },\n        {\n          \"foreground\": \"#ffa5d8\",\n          \"style\": \"diamond\",\n          \"template\": \"[{{ if .Error }}{{ .Error }}{{ else }}{{ if .Name }}<#ffffff>\\uf487</> {{ .Name }}{{ end }}{{ if .Target }} {{ .Target }}{{ end }}{{ end }}]\",\n          \"type\": \"project\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"leading_diamond\": \"<#7eb8da>\\u2523</>\",\n      \"segments\": [\n        {\n          \"foreground\": \"#7eb8da\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uf115</> <#98bfad>{{ .Path }}</>]\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#ffa5d8\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"[<#ffffff>{{ .UpstreamIcon }} </>{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} <#ffffff>\\uf044</> {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} <#ffffff>\\uf046</> {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} <#ffffff>\\ueb4b</> {{ .StashCount }}{{ end }}]\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"leading_diamond\": \"<#7eb8da>\\u2514\\u2500</>\",\n      \"segments\": [\n        {\n          \"style\": \"diamond\",\n            \"template\": \"<#ffff00>[#]</>\",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#ffa5d8\",\n          \"style\": \"diamond\",\n          \"template\": \"[<#ffffff>\\uea6c</> Error, check your command]\",\n          \"type\": \"status\"\n        },\n        {\n          \"style\": \"diamond\",\n          \"template\": \">\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"secondary_prompt\": {\n    \"background\": \"transparent\",\n    \"template\": \" \"\n  },\n  \"valid_line\": {\n    \"background\": \"transparent\",\n    \"template\": \"> \"\n  },\n  \"error_line\": {\n    \"background\": \"transparent\",\n    \"template\": \"<#ff0000>\\uea87</> \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/tokyonight_storm.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"console_title_template\": \" {{ .Folder }} :: {{if .Root}}Admin{{end}}\",\n  \"palette\": {\n    \"main-bg\": \"#24283b\",\n    \"terminal-red\": \"#f7768e\",\n    \"pistachio-green\": \"#9ece6a\",\n    \"terminal-green\": \"#73daca\",\n    \"terminal-yellow\": \"#e0af68\",\n    \"terminal-blue\": \"#7aa2f7\",\n    \"celeste-blue\": \"#b4f9f8\",\n    \"light-sky-blue\": \"#7dcfff\",\n    \"terminal-white\": \"#c0caf5\",\n    \"white-blue\": \"#a9b1d6\",\n    \"blue-bell\": \"#9aa5ce\",\n    \"pastal-grey\": \"#cfc9c2\",\n    \"terminal-magenta\": \"#bb9af7\",\n    \"blue-black\": \"#565f89\",\n    \"terminal-black\": \"#414868\",\n    \"t-background\": \"p:main-bg\"\n  },\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"type\": \"text\",\n          \"style\": \"plain\",\n          \"background\": \"transparent\",\n          \"foreground\": \"p:terminal-blue\",\n          \"template\": \"\\u279c \"\n        },\n        {\n          \"type\": \"path\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-magenta\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"template\": \"<b>{{ .Path }}</b> <p:light-sky-blue>\\u26a1</>\"\n        },\n        {\n          \"type\": \"git\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:light-sky-blue\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}p:terminal-red{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0)}}p:light-sky-blue {{ end }}\",\n            \"{{ if gt .Ahead 0 }}p:terminal-blue{{ end }}\",\n            \"{{ if gt .Behind 0 }}p:celeste-blue{{ end }}\"\n          ],\n          \"template\": \"({{ .HEAD}})\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"branch_icon\": \"\\ue725 \"\n          }\n        },\n        {\n          \"type\": \"status\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-red\",\n          \"template\": \" \\uf00d\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"overflow\": \"hide\",\n      \"segments\": [\n        {\n          \"type\": \"node\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:pistachio-green\",\n          \"template\": \"\\ue718 {{ .Full }} \"\n        },\n        {\n          \"type\": \"php\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-blue\",\n          \"template\": \"\\ue73d {{ .Full }} \"\n        },\n        {\n          \"type\": \"python\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-yellow\",\n          \"template\": \"\\uE235 {{ .Full }}\"\n        },\n        {\n          \"type\": \"julia\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-magenta\",\n          \"template\": \"\\uE624 {{ .Full }}\"\n        },\n        {\n          \"type\": \"ruby\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:terminal-red\",\n          \"template\": \"\\uE791 {{ .Full}}\"\n        },\n        {\n          \"type\": \"go\",\n          \"style\": \"plain\",\n          \"foreground\": \"p:light-sky-blue\",\n          \"template\": \"\\uFCD1 {{ .Full}}\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"p:pistachio-green\",\n          \"style\": \"plain\",\n          \"template\": \"\\u25b6\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"secondary_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"p:terminal-blue\",\n    \"template\": \"\\u279c \"\n  },\n  \"transient_prompt\": {\n    \"background\": \"p:t-background\",\n    \"foreground\": \"p:terminal-blue\",\n    \"template\": \"\\u279c \"\n  },\n  \"final_space\": true,\n  \"version\": 4,\n  \"terminal_background\": \"p:t-background\"\n}\n"
  },
  {
    "path": "themes/tonybaloney.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#18354c\",\n          \"foreground\": \"#ffc107\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#18354c\",\n          \"foreground\": \"#ffc107\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#ffc107\",\n          \"foreground\": \"#18354c\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\ue235 {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }} \",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#ffc107\",\n          \"foreground\": \"#18354c\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \" \\uf0e7 \",\n          \"type\": \"root\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/uew.omp.json",
    "content": "{\n    \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n    \"blocks\": [\n      {\n        \"alignment\": \"left\",\n        \"newline\": true,\n        \"segments\": [\n          {\n            \"foreground\": \"#BBC4B9\",\n            \"leading_diamond\":\"<#BFA8BF>~</> \",\n            \"style\": \"diamond\",\n            \"template\": \"{{ .UserName }} \",\n            \"type\": \"session\"\n          },\n          {\n            \"foreground\": \"#BFA8BF\",\n            \"options\": {\n              \"branch_icon\": \"\\ue725 \",\n              \"fetch_status\": true,\n              \"fetch_upstream_icon\": true\n            },\n            \"style\": \"diamond\",\n            \"template\": \"<#fff>{{ .UpstreamIcon }}</>{{ .HEAD }}\",\n            \"type\": \"git\"\n          },\n          {\n            \"foreground\": \"#BFA8BF\",\n            \"style\": \"powerline\",\n            \"template\": \" <#fff>\\uf120</> {{ .Name }} \",\n            \"type\": \"shell\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n      {\n        \"alignment\": \"right\",\n        \"segments\": [\n          {\n            \"foreground\": \"#fff\",\n            \"style\": \"plain\",\n            \"type\": \"text\"\n          },\n          {\n            \"foreground\": \"#fff\",\n            \"options\": {\n              \"style\": \"dallas\",\n              \"threshold\": 0\n            },\n            \"style\": \"diamond\",\n            \"template\": \" <#BBC4B9>{{ .FormattedMs }}s</> <#fff>\\udb80\\udddd</>\",\n            \"type\": \"executiontime\"\n          },\n          {\n            \"foreground\": \"#BBC4B9\",\n            \"options\": {\n              \"time_format\": \"Monday <#fff>at</> 3:04 PM\"\n            },\n            \"style\": \"diamond\",\n            \"template\": \" {{ .CurrentDate | date .Format }} \",\n            \"type\": \"time\"\n          },\n          {\n            \"options\": {\n              \"root_icon\": \"\\uf292 \"\n            },\n            \"style\": \"diamond\",\n            \"template\": \" \\uf0e7\",\n            \"type\": \"root\"\n          },\n          {\n            \"foreground\": \"#BBC4B9\",\n            \"style\": \"diamond\",\n            \"template\": \" <#fff>\\ue718</> {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }} \",\n            \"type\": \"node\"\n          }\n        ],\n        \"type\": \"prompt\"\n      },\n      {\n        \"alignment\": \"left\",\n        \"newline\": true,\n        \"segments\": [\n          {\n            \"foreground\": \"#B6D6F2\",\n            \"leading_diamond\": \"<#BFA8BF>~</>\",\n            \"options\": {\n              \"folder_icon\": \"\\u002F\",\n              \"folder_separator_icon\": \" \\u002F \",\n              \"home_icon\": \"home\",\n              \"style\": \"agnoster_full\"\n            },\n            \"style\": \"diamond\",\n            \"template\": \" \\ue5ff {{ .Path }}\",\n            \"trailing_diamond\": \"\",\n            \"type\": \"path\"\n          },\n          {\n            \"foreground\": \"#BFA8BF\",\n            \"foreground_templates\": [\n              \"{{ if gt .Code 0 }}#fff{{ end }}\"\n            ],\n            \"options\": {\n              \"always_enabled\": true\n            },\n            \"style\": \"plain\",\n            \"template\": \" \\u007E \",\n            \"type\": \"status\"\n          }\n        ],\n        \"type\": \"prompt\"\n      }\n    ],\n    \"console_title_template\": \"{{ .Folder }}\",\n    \"transient_prompt\": {\n      \"background\": \"transparent\",\n      \"foreground\": \"#FEF5ED\",\n      \"template\": \"\\ue285 \"\n    },\n    \"version\": 4\n  }\n"
  },
  {
    "path": "themes/unicorn.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#fff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"windows\": \"\\ue62a \"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#0087D8\",\n          \"foreground\": \"#003544\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"folder_separator_icon\": \"/\",\n            \"style\": \"full\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#d2ff5e\",\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}#ff9248{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#f26d50{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#89d1dc{{ end }}\",\n            \"{{ if gt .Behind 0 }}#f17c37{{ end }}\"\n          ],\n          \"foreground\": \"#193549\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"options\": {\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#003543\",\n          \"foreground\": \"#fff\",\n          \"powerline_symbol\": \"\\ue0b0\",\n          \"style\": \"powerline\",\n          \"template\": \"<#fff> \\ue641 </>{{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#83769c\",\n          \"foreground\": \"#ffffff\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ueba2 {{ .FormattedMs }}\\u2800\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#fff\",\n          \"style\": \"plain\",\n          \"template\": \" \\u26a1 \",\n          \"type\": \"root\"\n        },\n        {\n          \"foreground\": \"#f1184c\",\n          \"style\": \"plain\",\n          \"template\": \"🦄 \",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{.UserName}}@{{.HostName}} in {{ .PWD }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/velvet.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#0E050F\",\n          \"foreground\": \"#EFDCF9\",\n          \"options\": {\n            \"arch\": \"\\uf303\",\n            \"debian\": \"\\uf306\",\n            \"fedora\": \"\\uf30a\",\n            \"linux\": \"\\uf17c\",\n            \"macos\": \"\\uf179\",\n            \"manjaro\": \"\\uf312\",\n            \"opensuse\": \"\\uf314\",\n            \"ubuntu\": \"\\uf31b\",\n            \"windows\": \"\\uf17a\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}} \",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#170B3B\",\n          \"foreground\": \"#EFDCF9\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"options\": {\n            \"folder_icon\": \"...\",\n            \"folder_separator_icon\": \"/\",\n            \"home_icon\": \"~\",\n            \"max_depth\": 3,\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"background\": \"#341948\",\n          \"foreground\": \"#EFDCF9\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"options\": {\n            \"branch_template\": \"{{ trunc 25 .Branch }}\",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#EFDCF9\",\n          \"powerline_symbol\": \"\\ue0b4\",\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"type\": \"executiontime\"\n        },\n        {\n          \"background\": \"#69307A\",\n          \"foreground\": \"#EFDCF9\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#FF3C3C{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\uf08a{{ if gt .Code 0 }} {{.Code}}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#E4F34A\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue235{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"python\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#7FD5EA\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue626{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"go\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#42E66C\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue791{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#E64747\",\n          \"leading_diamond\": \" \\ue0b6\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue738{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"java\"\n        }\n      ],\n      \"type\": \"rprompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"background\": \"#4c1f5e\",\n          \"foreground\": \"#EFDCF9\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Shell }} - {{ .Folder }}\",\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/wholespace.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#FEF5ED\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"macos\": \"\\uf179 \",\n            \"ubuntu\": \"\\uf31b \",\n            \"windows\": \"\\ue62a \"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\",\n          \"trailing_diamond\": \"<transparent,#FEF5ED>\\ue0b2</>\",\n          \"type\": \"os\"\n        },\n        {\n          \"background\": \"#FEF5ED\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"time_format\": \"15:04:05\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\u2665 {{ .CurrentDate | date .Format }} \",\n          \"trailing_diamond\": \"<transparent,#FEF5ED>\\ue0b2</>\",\n          \"type\": \"time\"\n        },\n        {\n          \"background\": \"#516BEB\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"style\": \"diamond\",\n          \"template\": \"\\ue266 CPU: {{ round .PhysicalPercentUsed .Precision }}% | \",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#516BEB\",\n          \"foreground\": \"#ffffff\",\n          \"style\": \"diamond\",\n          \"template\": \"RAM: {{ (div ((sub .PhysicalTotalMemory .PhysicalAvailableMemory)|float64) 1073741824.0) }}/{{ (div .PhysicalTotalMemory 1073741824.0) }}GB \\ue266 \",\n          \"trailing_diamond\": \"<transparent,#516BEB>\\ue0b2</>\",\n          \"type\": \"sysinfo\"\n        },\n        {\n          \"background\": \"#575656\",\n          \"foreground\": \"#d6deeb\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"style\": \"roundrock\",\n            \"threshold\": 0\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .FormattedMs }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"executiontime\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"background\": \"#ffffff\",\n          \"foreground\": \"#000000\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"fetch_package_manager\": true,\n            \"npm_icon\": \" <#cc3a3a>\\ue5fa</> \",\n            \"yarn_icon\": \" <#348cba>\\ue6a7</>\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \"\\ue718 {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"trailing_diamond\": \"<transparent,#ffffff>\\ue0b2</>\",\n          \"type\": \"node\"\n        },\n        {\n          \"background\": \"#17D7A0\",\n          \"foreground\": \"#011627\",\n          \"leading_diamond\": \"\\ue0b2\",\n          \"options\": {\n            \"branch_icon\": \"\\ue725 \",\n            \"fetch_status\": true,\n            \"fetch_upstream_icon\": true\n          },\n          \"style\": \"diamond\",\n          \"template\": \" {{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\ueb4b {{ .StashCount }}{{ end }} \",\n          \"trailing_diamond\": \"\\ue0b0\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"#ffafd2\",\n          \"options\": {\n            \"folder_icon\": \"\\uf07b\",\n            \"home_icon\": \"home\",\n            \"style\": \"agnoster_full\"\n          },\n          \"style\": \"diamond\",\n          \"template\": \" \\ue5ff {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#00ff15\",\n          \"foreground_templates\": [\"{{ if gt .Code 0 }}#ff0000{{ end }}\"],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" \\ueb05 \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"console_title_template\": \"{{ .Folder }}\",\n  \"transient_prompt\": {\n    \"background\": \"transparent\",\n    \"foreground\": \"#FEF5ED\",\n    \"template\": \"\\ue285 \"\n  },\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/wopian.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"cyan\",\n          \"style\": \"powerline\",\n          \"template\": \"{{ .Icon }}\",\n          \"type\": \"os\"\n        },\n        {\n          \"foreground\": \"cyan\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"lightYellow\",\n          \"style\": \"plain\",\n          \"template\": \":: <lightBlue>git(</>{{ .HEAD }}<lightBlue>)</>\",\n          \"type\": \"git\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"foreground\": \"#68a063\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_package_manager\": true,\n            \"fetch_version\": true,\n            \"npm_icon\": \"/npm\",\n            \"yarn_icon\": \"/yarn\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\",\n          \"type\": \"node\"\n        },\n        {\n          \"foreground\": \"#4063D8\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"crystal\"\n        },\n        {\n          \"foreground\": \"#DE3F24\",\n          \"options\": {\n            \"display_mode\": \"files\",\n            \"fetch_version\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"ruby\"\n        },\n        {\n          \"foreground\": \"#FED142\",\n          \"options\": {\n            \"display_mode\": \"context\",\n            \"fetch_virtual_env\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\",\n          \"type\": \"python\"\n        },\n        {\n          \"foreground\": \"lightGreen\",\n          \"style\": \"plain\",\n          \"template\": \" {{ .CurrentDate | date .Format }} \",\n          \"type\": \"time\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightGreen\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}red{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"powerline\",\n          \"template\": \"\\u279c \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/xtoys.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#CECE04\",\n          \"style\": \"plain\",\n          \"template\": \"# \",\n          \"type\": \"root\"\n        },\n        {\n          \"style\": \"plain\",\n          \"template\": \"{{ .UserName }}@{{ .HostName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#7B68EE\",\n          \"options\": {\n            \"style\": \"agnoster_short\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#48D1CC\",\n          \"options\": {\n            \"branch_icon\": \"\",\n            \"fetch_upstream_icon\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \"HEAD:{{ .UpstreamIcon }}{{ .HEAD }} \",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#7FFFD4\",\n          \"foreground_templates\": [\n            \"{{ if gt .Code 0 }}#E84855{{ end }}\"\n          ],\n          \"options\": {\n            \"always_enabled\": true\n          },\n          \"style\": \"plain\",\n          \"template\": \"<#66CDAA>\\u276f</><#76EEC6>\\u276f</><foreground>\\u276f</> \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/ys.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"white\",\n          \"options\": {\n            \"fetch_version\": false\n          },\n          \"style\": \"plain\",\n          \"template\": \"({{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }})\",\n          \"type\": \"python\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightBlue\",\n          \"style\": \"plain\",\n          \"template\": \"# \",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"red\",\n          \"style\": \"plain\",\n          \"template\": \" % \",\n          \"type\": \"root\"\n        },\n        {\n          \"style\": \"plain\",\n          \"template\": \"<cyan>{{ .UserName }}</> <darkGray>@</> <green>{{ .HostName }}</> \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"lightYellow\",\n          \"options\": {\n            \"style\": \"full\"\n          },\n          \"style\": \"plain\",\n          \"template\": \"<darkGray>in </>{{ .Path }} \",\n          \"type\": \"path\"\n        },\n        {\n          \"style\": \"plain\",\n          \"template\": \"<darkGray>on</> <white>git:</><cyan>{{ .HEAD }}</>{{ if .Working.Changed }}<red> x</>{{ end }} \",\n          \"type\": \"git\",\n          \"options\": {\n            \"fetch_status\": true\n          }\n        },\n        {\n          \"foreground\": \"darkGray\",\n          \"style\": \"plain\",\n          \"template\": \"[{{ .CurrentDate | date .Format }}]\",\n          \"type\": \"time\"\n        },\n        {\n          \"foreground\": \"red\",\n          \"style\": \"plain\",\n          \"template\": \" C:{{ if gt .Code 0 }}{{ .Code }}{{ end }} \",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    },\n    {\n      \"alignment\": \"left\",\n      \"newline\": true,\n      \"segments\": [\n        {\n          \"foreground\": \"lightRed\",\n          \"style\": \"plain\",\n          \"template\": \"$\",\n          \"type\": \"text\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "themes/zash.omp.json",
    "content": "{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"blocks\": [\n    {\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"foreground\": \"#E36464\",\n          \"style\": \"plain\",\n          \"template\": \"@{{ .UserName }} \",\n          \"type\": \"session\"\n        },\n        {\n          \"foreground\": \"#62ED8B\",\n          \"style\": \"plain\",\n          \"template\": \"\\u279c\",\n          \"type\": \"text\"\n        },\n        {\n          \"foreground\": \"#56B6C2\",\n          \"options\": {\n            \"style\": \"folder\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" {{ .Path }}\",\n          \"type\": \"path\"\n        },\n        {\n          \"foreground\": \"#D4AAFC\",\n          \"options\": {\n            \"branch_icon\": \"\"\n          },\n          \"style\": \"plain\",\n          \"template\": \" <#DDB15F>git(</>{{ .HEAD }}<#DDB15F>)</>\",\n          \"type\": \"git\"\n        },\n        {\n          \"foreground\": \"#DCB977\",\n          \"style\": \"plain\",\n          \"template\": \" \\uf119\",\n          \"type\": \"status\"\n        }\n      ],\n      \"type\": \"prompt\"\n    }\n  ],\n  \"final_space\": true,\n  \"version\": 4\n}\n"
  },
  {
    "path": "website/.gitignore",
    "content": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "website/README.md",
    "content": "# Website\n\nThis website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.\n\n## Installation\n\n```shell\nnpm install\n```\n\n## Local Development\n\n```shell\nnpm run start\n```\n\nThis command starts a local development server and open up a browser window.\nMost changes are reflected live without having to restart the server.\n"
  },
  {
    "path": "website/api/.funcignore",
    "content": "*.js.map\n*.ts\n.git*\n.vscode\nlocal.settings.json\ntest\ntsconfig.json"
  },
  {
    "path": "website/api/.gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# TypeScript v1 declaration files\ntypings/\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variables file\n.env\n.env.test\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n\n# next.js build output\n.next\n\n# nuxt.js build output\n.nuxt\n\n# vuepress build output\n.vuepress/dist\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TypeScript output\ndist\nout\n\n# Azure Functions artifacts\nbin\nobj\nappsettings.json\nlocal.settings.json\n\n# Azurite artifacts\n__blobstorage__\n__queuestorage__\n__azurite_db*__.json"
  },
  {
    "path": "website/api/auth/function.json",
    "content": "{\n  \"bindings\": [\n    {\n      \"authLevel\": \"anonymous\",\n      \"type\": \"httpTrigger\",\n      \"direction\": \"in\",\n      \"name\": \"req\",\n      \"methods\": [\n        \"get\",\n        \"post\"\n      ]\n    },\n    {\n      \"type\": \"http\",\n      \"direction\": \"out\",\n      \"name\": \"res\"\n    }\n  ]\n}\n"
  },
  {
    "path": "website/api/auth/index.js",
    "content": "const strava = require('../shared/strava.js');\nconst withings = require('../shared/withings.js');\n\nmodule.exports = async function (context, req) {\n  context.log('Auth function processed a request');\n  // strava example:\n  // https://www.strava.com/oauth/authorize?client_id=76033&response_type=code&redirect_uri=https://ohmyposh.dev/api/auth&approval_prompt=force&scope=read,activity:read&state=strava\n  const code = (req.query.code || req.query._code || (req.body && req.body.code));\n  const segment = (req.query.state || (req.body && req.body.state));\n  let tokens = {\n    access_token: '',\n    refresh_token: '',\n    expires_in: '',\n  };\n  try {\n    if (!code || !segment) {\n      context.log(`Issue processing request: missing code (${code}) or segment (${segment})`);\n      redirect(context, segment, tokens, 'missing code or segment');\n      return;\n    }\n\n    context.log(`Processing the ${segment} code`);\n\n    switch (segment) {\n      case \"strava\":\n        tokens = await strava.getToken(code);\n        break;\n      case \"withings\":\n        tokens = await withings.getToken(code);\n        break;\n      default:\n        context.log(`Unknown segment: ${segment}`);\n        redirect(context, segment, tokens, `Unknown segment: ${segment}`);\n        return;\n    }\n\n    redirect(context, segment, tokens, '');\n  } catch (error) {\n    if (!error.stack) {\n      redirect(context, segment, tokens, toBase64(error));\n      return;\n    }\n    context.log(`Error: ${error.stack}`);\n    redirect(context, segment, tokens, toBase64(error.stack));\n  }\n}\n\nfunction toBase64(str) {\n  return Buffer.from(str).toString('base64');\n}\n\nfunction redirect(context, segment, tokens, error) {\n  const url = `${process.env['DOCS_LOCATION']}/docs/auth?segment=${segment}&access_token=${tokens.access_token}&refresh_token=${tokens.refresh_token}&expires_in=${tokens.expires_in}&error=${error}`;\n  context.res = {\n    status: 302,\n    headers: {\n      Location: url\n    },\n    body: {}\n  }\n  context.done();\n}\n"
  },
  {
    "path": "website/api/data/.gitignore",
    "content": "# Schema is copied during build from themes/schema.json\nschema.json\n"
  },
  {
    "path": "website/api/data/README.md",
    "content": "# API Data Directory\n\nThis directory contains data files used by the Azure Functions API.\n\n## Schema File\n\nThe `schema.json` file is automatically copied from `themes/schema.json` during the GitHub Actions\ndeployment workflow. This file is used by the MCP validator to validate oh-my-posh configurations.\n\nThe schema is embedded locally to:\n\n- Improve performance (no external HTTP requests)\n- Ensure reliability (no dependency on external services)\n- Work offline/in isolated environments\n"
  },
  {
    "path": "website/api/host.json",
    "content": "{\n  \"version\": \"2.0\",\n  \"logging\": {\n    \"applicationInsights\": {\n      \"samplingSettings\": {\n        \"isEnabled\": true,\n        \"excludedTypes\": \"Request\"\n      }\n    }\n  },\n  \"extensionBundle\": {\n    \"id\": \"Microsoft.Azure.Functions.ExtensionBundle\",\n    \"version\": \"[2.*, 3.0.0)\"\n  }\n}\n"
  },
  {
    "path": "website/api/mcp/.gitignore",
    "content": "server.schema.json\n"
  },
  {
    "path": "website/api/mcp/.well-known/mcp.json",
    "content": "{\n  \"name\": \"oh-my-posh-validator\",\n  \"description\": \"MCP server for validating oh-my-posh theme configurations against the official JSON schema. Supports JSON, YAML, and TOML formats with detailed error reporting.\",\n  \"version\": \"1.0.0\",\n  \"author\": {\n    \"name\": \"Jan De Dobbeleer\",\n    \"url\": \"https://github.com/JanDeDobbeleer\"\n  },\n  \"homepage\": \"https://ohmyposh.dev\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/JanDeDobbeleer/oh-my-posh\"\n  },\n  \"license\": \"MIT\",\n  \"transport\": {\n    \"type\": \"http\",\n    \"url\": \"https://ohmyposh.dev/api/mcp\"\n  },\n  \"capabilities\": {\n    \"tools\": [\n      {\n        \"name\": \"validate_config\",\n        \"description\": \"Validates oh-my-posh configuration files (JSON, YAML, or TOML) against the official schema. Returns detailed validation errors with JSON paths and helpful suggestions.\"\n      }\n    ]\n  },\n  \"keywords\": [\n    \"oh-my-posh\",\n    \"prompt\",\n    \"theme\",\n    \"validation\",\n    \"schema\",\n    \"json-schema\",\n    \"yaml\",\n    \"toml\",\n    \"configuration\"\n  ]\n}\n"
  },
  {
    "path": "website/api/mcp/README.md",
    "content": "---\ntitle: MCP Validator Function\ndescription: 'Azure Function implementing the Model Context Protocol server for validating oh-my-posh configurations'\n---\n\n## Overview\n\nThis directory contains the Azure Function that implements the Model Context Protocol (MCP) server for\nvalidating oh-my-posh configurations.\n\n## Endpoints\n\n- `POST /api/mcp` - MCP server endpoint that handles validation requests\n- `GET /api/mcp` - Returns server information and available tools\n\n## Supported Tools\n\n### validate_config\n\nValidate an oh-my-posh configuration.\n\n- Supports JSON, YAML, and TOML formats\n- Returns detailed validation errors with JSON paths\n\n### validate_segment\n\nValidate a segment snippet (individual prompt segment).\n\n- Validates against the segment schema definition\n- Useful for testing individual segments before adding them to a full configuration\n- Supports JSON, YAML, and TOML formats\n\n## Usage\n\n### As an MCP Server\n\nConfigure your MCP client to connect to this server:\n\n```json\n{\n  \"mcpServers\": {\n    \"oh-my-posh-validator\": {\n      \"url\": \"https://ohmyposh.dev/api/mcp\",\n      \"transport\": \"http\"\n    }\n  }\n}\n```\n\n### Direct HTTP Requests\n\n#### Get Server Info\n\n```bash\ncurl https://ohmyposh.dev/api/mcp\n```\n\n#### List Available Tools\n\n```bash\ncurl -X POST https://ohmyposh.dev/api/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"tools/list\",\n    \"id\": 1\n  }'\n```\n\n#### Validate a Configuration\n\n```bash\ncurl -X POST https://ohmyposh.dev/api/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"tools/call\",\n    \"params\": {\n      \"name\": \"validate_config\",\n      \"arguments\": {\n        \"content\": \"{\\\"$schema\\\":\\\"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/\nthemes/schema.json\\\",\\\"blocks\\\":[]}\",\n        \"format\": \"json\"\n      }\n    },\n    \"id\": 1\n  }'\n```\n\n#### Validate a Segment Snippet\n\n```bash\ncurl -X POST https://ohmyposh.dev/api/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"tools/call\",\n    \"params\": {\n      \"name\": \"validate_segment\",\n      \"arguments\": {\n        \"content\": \"{\\\"type\\\":\\\"path\\\",\\\"style\\\":\\\"powerline\\\",\\\"foreground\\\":\\\"#ffffff\\\",\\\"background\\\":\\\"#61AFEF\\\",\\\"template\\\":\\\" {{ .Path }} \\\"}\",\n        \"format\": \"json\"\n      }\n    },\n    \"id\": 2\n  }'\n```\n\n## Response Format\n\nThe validation result includes:\n\n- `valid`: Boolean indicating if the configuration is valid\n- `errors`: Array of validation errors (if any)\n- `warnings`: Array of warnings (best practices, deprecations)\n- `detectedFormat`: The detected or specified format\n- `parsedConfig`: The parsed configuration object (for debugging)\n\nExample response:\n\n```json\n{\n  \"jsonrpc\": \"2.0\",\n  \"result\": {\n    \"content\": [\n      {\n        \"type\": \"text\",\n        \"text\": \"{\n          \\\"valid\\\": true,\n          \\\"errors\\\": [],\n          \\\"warnings\\\": [\n            {\n              \\\"path\\\": \\\"$schema\\\",\n              \\\"message\\\": \\\"Consider adding \\\\\\\"$schema\\\\\\\" property for better editor support.\\\",\n              \\\"type\\\": \\\"recommendation\\\"\n            }\n          ],\n          \\\"detectedFormat\\\": \\\"json\\\",\n          \\\"parsedConfig\\\": {...}\n        }\"\n      }\n    ]\n  },\n  \"id\": 1\n}\n```\n\n## Development\n\nTo test locally:\n\n```bash\ncd website/api\nnpm install\nnpm start\n```\n\nThen send requests to `http://localhost:7071/api/mcp`\n\n## Publishing to MCP Registry\n\nThis server is published to the [MCP Registry](https://github.com/modelcontextprotocol/registry) using GitHub Actions.\n\n### Publishing\n\nPublishing is triggered automatically when you push a version tag (same as oh-my-posh releases):\n\n```bash\ngit tag v9.0.0\ngit push origin v9.0.0\n```\n\nThe workflow will:\n\n1. Extract version from the tag (e.g., `v9.0.0` → `9.0.0`)\n2. Update `server.json` version to match\n3. Validate the `server.json` file\n4. Authenticate with the MCP Registry using GitHub OIDC\n5. Publish the server to the registry\n\n**Note**: The MCP server version will stay in sync with oh-my-posh versions automatically.\n\n### Files\n\n- `server.json` - MCP Registry server configuration\n- `server.schema.json` - JSON schema for validation\n- `validate-server.js` - Validation script\n- `.github/workflows/publish-mcp.yml` - GitHub Actions workflow\n\n### Validating server.json Locally\n\n```bash\ncd website/api\nnpm install\ncd mcp\nnode validate-server.js\n```\n"
  },
  {
    "path": "website/api/mcp/function.json",
    "content": "{\n  \"bindings\": [\n    {\n      \"authLevel\": \"anonymous\",\n      \"type\": \"httpTrigger\",\n      \"direction\": \"in\",\n      \"name\": \"req\",\n      \"methods\": [\n        \"post\",\n        \"get\"\n      ]\n    },\n    {\n      \"type\": \"http\",\n      \"direction\": \"out\",\n      \"name\": \"res\"\n    }\n  ]\n}\n"
  },
  {
    "path": "website/api/mcp/index.js",
    "content": "const validator = require('../shared/validator.js');\n\n/**\n * Azure Function entry point for MCP server\n */\nmodule.exports = async function (context, req) {\n  context.log('MCP validator function processed a request');\n\n  // Handle GET requests - return server info\n  if (req.method === 'GET') {\n    context.res = {\n      status: 200,\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: {\n        name: 'oh-my-posh-validator',\n        version: '1.0.0',\n        description: 'MCP server for validating oh-my-posh configurations',\n        capabilities: {\n          tools: {}\n        },\n        tools: [\n          {\n            name: 'validate_config',\n            description: 'Validate an oh-my-posh configuration against the schema',\n            inputSchema: {\n              type: 'object',\n              properties: {\n                content: {\n                  type: 'string',\n                  description: 'The configuration content as a string (JSON, YAML, or TOML)'\n                },\n                format: {\n                  type: 'string',\n                  enum: ['json', 'yaml', 'toml', 'auto'],\n                  description: 'The format of the configuration (auto-detect if not specified)',\n                  default: 'auto'\n                }\n              },\n              required: ['content']\n            }\n          },\n          {\n            name: 'validate_segment',\n            description: 'Validate a segment snippet against the oh-my-posh schema',\n            inputSchema: {\n              type: 'object',\n              properties: {\n                content: {\n                  type: 'string',\n                  description: 'The segment content as a string (JSON, YAML, or TOML)'\n                },\n                format: {\n                  type: 'string',\n                  enum: ['json', 'yaml', 'toml', 'auto'],\n                  description: 'The format of the segment (auto-detect if not specified)',\n                  default: 'auto'\n                }\n              },\n              required: ['content']\n            }\n          }\n        ]\n      }\n    };\n    return;\n  }\n\n  // Handle POST requests - process MCP protocol messages\n  try {\n    // Parse the body if it's a string\n    let message = req.body;\n    if (typeof message === 'string') {\n      try {\n        message = JSON.parse(message);\n      } catch (e) {\n        context.log.error('Failed to parse request body as JSON:', e);\n        context.res = {\n          status: 400,\n          headers: {\n            'Content-Type': 'application/json'\n          },\n          body: {\n            jsonrpc: '2.0',\n            error: {\n              code: -32700,\n              message: 'Parse error: Invalid JSON'\n            },\n            id: null\n          }\n        };\n        return;\n      }\n    }\n\n    const logMessage = {\n      jsonrpc: message.jsonrpc,\n      method: message.method,\n      id: message.id,\n      ...(message.params?.name && { toolName: message.params.name })\n    };\n    context.log('Received message:', JSON.stringify(logMessage));\n\n    if (!message || !message.jsonrpc || message.jsonrpc !== '2.0') {\n      context.log('Invalid JSON-RPC message:', message);\n      context.res = {\n        status: 400,\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: {\n          jsonrpc: '2.0',\n          error: {\n            code: -32600,\n            message: 'Invalid Request: Not a valid JSON-RPC 2.0 message'\n          },\n          id: message?.id || null\n        }\n      };\n      return;\n    }\n\n    // Handle list tools request\n    if (message.method === 'tools/list') {\n      context.res = {\n        status: 200,\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: {\n          jsonrpc: '2.0',\n          result: {\n            tools: [\n              {\n                name: 'validate_config',\n                description: 'Validate an oh-my-posh configuration against the schema. Supports JSON, YAML, and TOML formats.',\n                inputSchema: {\n                  type: 'object',\n                  properties: {\n                    content: {\n                      type: 'string',\n                      description: 'The configuration content as a string (JSON, YAML, or TOML)'\n                    },\n                    format: {\n                      type: 'string',\n                      enum: ['json', 'yaml', 'toml', 'auto'],\n                      description: 'The format of the configuration (auto-detect if not specified)',\n                      default: 'auto'\n                    }\n                  },\n                  required: ['content']\n                }\n              },\n              {\n                name: 'validate_segment',\n                description: 'Validate a segment snippet against the oh-my-posh schema. Useful for validating individual prompt segments before adding them to a configuration.',\n                inputSchema: {\n                  type: 'object',\n                  properties: {\n                    content: {\n                      type: 'string',\n                      description: 'The segment content as a string (JSON, YAML, or TOML)'\n                    },\n                    format: {\n                      type: 'string',\n                      enum: ['json', 'yaml', 'toml', 'auto'],\n                      description: 'The format of the segment (auto-detect if not specified)',\n                      default: 'auto'\n                    }\n                  },\n                  required: ['content']\n                }\n              }\n            ]\n          },\n          id: message.id\n        }\n      };\n      return;\n    }\n\n    // Handle tool call request\n    if (message.method === 'tools/call') {\n      const { name, arguments: args } = message.params;\n\n      let result;\n      \n      if (name === 'validate_config') {\n        result = await validator.validateConfig(args.content, args.format || 'auto');\n      } else if (name === 'validate_segment') {\n        result = await validator.validateSegment(args.content, args.format || 'auto');\n      } else {\n        context.res = {\n          status: 200,\n          headers: {\n            'Content-Type': 'application/json'\n          },\n          body: {\n            jsonrpc: '2.0',\n            error: {\n              code: -32601,\n              message: `Unknown tool: ${name}`\n            },\n            id: message.id\n          }\n        };\n        return;\n      }\n\n      context.res = {\n        status: 200,\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: {\n          jsonrpc: '2.0',\n          result: {\n            content: [\n              {\n                type: 'text',\n                text: JSON.stringify(result, null, 2)\n              }\n            ]\n          },\n          id: message.id\n        }\n      };\n      return;\n    }\n\n    // Handle initialize request\n    if (message.method === 'initialize') {\n      context.res = {\n        status: 200,\n        headers: {\n          'Content-Type': 'application/json'\n        },\n        body: {\n          jsonrpc: '2.0',\n          result: {\n            protocolVersion: '2024-11-05',\n            capabilities: {\n              tools: {}\n            },\n            serverInfo: {\n              name: 'oh-my-posh-validator',\n              version: '1.0.0'\n            }\n          },\n          id: message.id\n        }\n      };\n      return;\n    }\n\n    // Unknown method\n    context.res = {\n      status: 200,\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: {\n        jsonrpc: '2.0',\n        error: {\n          code: -32601,\n          message: `Method not found: ${message.method}`\n        },\n        id: message.id\n      }\n    };\n\n  } catch (error) {\n    context.log.error('Error processing MCP request:', error);\n    context.res = {\n      status: 500,\n      headers: {\n        'Content-Type': 'application/json'\n      },\n      body: {\n        jsonrpc: '2.0',\n        error: {\n          code: -32603,\n          message: 'Internal error',\n          data: error.message\n        },\n        id: req.body?.id || null\n      }\n    };\n  }\n};\n"
  },
  {
    "path": "website/api/mcp/server.json",
    "content": "{\n  \"$schema\": \"https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json\",\n  \"name\": \"dev.ohmyposh/validator\",\n  \"title\": \"Oh My Posh Validator\",\n  \"description\": \"Validate oh-my-posh configurations and segment snippets against the official schema.\",\n  \"version\": \"1.0.0\",\n  \"license\": \"MIT\",\n  \"websiteUrl\": \"https://ohmyposh.dev/docs/advanced/mcp-server\",\n  \"repository\": {\n    \"url\": \"https://github.com/JanDeDobbeleer/oh-my-posh\",\n    \"source\": \"github\",\n    \"id\": \"175405157\",\n    \"subfolder\": \"website/api/mcp\"\n  },\n  \"author\": {\n    \"name\": \"Jan De Dobbeleer\",\n    \"email\": \"jan@ohmyposh.dev\",\n    \"url\": \"https://github.com/JanDeDobbeleer\"\n  },\n  \"keywords\": [\n    \"oh-my-posh\",\n    \"prompt\",\n    \"theme\",\n    \"validation\",\n    \"schema\",\n    \"json-schema\",\n    \"yaml\",\n    \"toml\",\n    \"configuration\",\n    \"terminal\"\n  ],\n  \"remotes\": [\n    {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://ohmyposh.dev/api/mcp\"\n    }\n  ]\n}\n"
  },
  {
    "path": "website/api/mcp/validate-server.js",
    "content": "const Ajv = require(\"ajv\");\nconst addFormats = require(\"ajv-formats\");\nconst fs = require(\"fs\");\nconst https = require(\"https\");\n\nconst ajv = new Ajv({ strict: false, allErrors: true });\naddFormats(ajv);\n\n// Download schema if not present\nconst schemaPath = \"server.schema.json\";\nconst schemaUrl = \"https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json\";\n\nfunction downloadSchema() {\n  return new Promise((resolve, reject) => {\n    https.get(schemaUrl, (res) => {\n      if (res.statusCode !== 200) {\n        // Consume response data to free up memory\n        res.resume();\n        reject(new Error(`Failed to download schema: HTTP status code ${res.statusCode}`));\n        return;\n      }\n      let data = \"\";\n      res.on(\"data\", (chunk) => data += chunk);\n      res.on(\"end\", () => {\n        fs.writeFileSync(schemaPath, data);\n        resolve(JSON.parse(data));\n      });\n    }).on(\"error\", reject);\n  });\n}\n\nasync function validateServer() {\n  let schema;\n  \n  // Load or download schema\n  if (fs.existsSync(schemaPath)) {\n    schema = JSON.parse(fs.readFileSync(schemaPath, \"utf8\"));\n  } else {\n    console.log(\"Downloading schema...\");\n    schema = await downloadSchema();\n  }\n\n  // Load server.json\n  const serverJsonPath = \"server.json\";\n  if (!fs.existsSync(serverJsonPath)) {\n    throw new Error(`server.json not found at ${serverJsonPath}`);\n  }\n  const serverJson = JSON.parse(fs.readFileSync(serverJsonPath, \"utf8\"));\n\n  // Validate\n  const validate = ajv.compile(schema);\n  const valid = validate(serverJson);\n\n  if (valid) {\n    console.log(\"✅ server.json is valid!\");\n    console.log(`   Name: ${serverJson.name}`);\n    console.log(`   Version: ${serverJson.version}`);\n    console.log(`   Transport: ${serverJson.remotes?.[0]?.type || 'N/A'}`);\n    process.exit(0);\n  } else {\n    console.error(\"❌ Validation errors:\");\n    validate.errors.forEach(err => {\n      console.error(`   ${err.instancePath}: ${err.message}`);\n      if (err.params) {\n        console.error(`   Details: ${JSON.stringify(err.params)}`);\n      }\n    });\n    process.exit(1);\n  }\n}\n\nvalidateServer().catch(err => {\n  console.error(\"Error:\", err.message);\n  process.exit(1);\n});\n"
  },
  {
    "path": "website/api/package.json",
    "content": "{\n  \"name\": \"api\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"scripts\": {\n    \"start\": \"func start\",\n    \"test\": \"node --test test/**/*.test.js\"\n  },\n  \"dependencies\": {\n    \"axios\": \"^1.13.2\",\n    \"ajv\": \"^8.17.1\",\n    \"ajv-formats\": \"^3.0.1\",\n    \"js-yaml\": \"^4.1.1\",\n    \"@iarna/toml\": \"^2.2.5\",\n    \"@modelcontextprotocol/sdk\": \"^1.25.1\"\n  }\n}\n"
  },
  {
    "path": "website/api/proxies.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/proxies\",\n  \"proxies\": {\n    \"callback\": {\n      \"debug\": true,\n      \"matchCondition\": {\n        \"methods\": [\"GET\", \"POST\"],\n        \"route\": \"/api/auth\"\n      },\n      \"backendUri\": \"https://localhost/api/auth\",\n      \"requestOverrides\": {\n        \"backend.request.querystring.code\": \"\",\n        \"backend.request.querystring._code\": \"{request.querystring.code}\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "website/api/refresh/function.json",
    "content": "{\n  \"bindings\": [\n    {\n      \"authLevel\": \"anonymous\",\n      \"type\": \"httpTrigger\",\n      \"direction\": \"in\",\n      \"name\": \"req\",\n      \"methods\": [\n        \"get\",\n        \"post\"\n      ]\n    },\n    {\n      \"type\": \"http\",\n      \"direction\": \"out\",\n      \"name\": \"res\"\n    }\n  ]\n}\n"
  },
  {
    "path": "website/api/refresh/index.js",
    "content": "const strava = require('../shared/strava.js');\nconst withings = require('../shared/withings.js');\n\nmodule.exports = async function (context, req) {\n  context.log('Refresh function processed a request');\n  // strava example:\n  // https://ohmyposh.dev/api/refresh?segment=strava&token=<refresh_token>\n\n  try {\n    const refresh_token = (req.query.token || (req.body && req.body.token));\n    const segment = (req.query.segment || (req.body && req.body.segment));\n    if (!refresh_token || !segment) {\n      context.res = {\n        status: 400\n      };\n      return;\n    }\n\n    context.log(`Refreshing the ${segment} token`);\n    let body = null;\n    switch (segment) {\n      case \"strava\":\n        body = await strava.refreshToken(refresh_token);\n        break;\n      case \"withings\":\n        body = await withings.refreshToken(refresh_token);\n        break;\n      default:\n        context.log(`Unknown segment: ${segment}`);\n        context.res = {\n          body: \"Unknown segment\",\n          status: 400\n        };\n        return;\n    }\n\n    context.res.json(body);\n  } catch (error) {\n    context.log(error);\n    context.res = {\n      body: {\n        \"message\": (error.message) ? error.message : \"unable to refresh token\"\n      },\n      status: 500\n    };\n  }\n}\n"
  },
  {
    "path": "website/api/shared/strava.js",
    "content": "const axios = require('axios');\n\nasync function getToken(code) {\n  const params = {\n    client_id: process.env['STRAVA_CLIENT_ID'],\n    client_secret: process.env['STRAVA_CLIENT_SECRET'],\n    code: code,\n    grant_type: 'authorization_code',\n  };\n  const resp = await axios.post('https://www.strava.com/api/v3/oauth/token', null, { params: params });\n\n  return {\n    access_token: resp.data.access_token,\n    refresh_token: resp.data.refresh_token,\n    expires_in: resp.data.expires_in\n  };\n}\n\nasync function refreshToken(refresh_token) {\n  const params = {\n    client_id: process.env['STRAVA_CLIENT_ID'],\n    client_secret: process.env['STRAVA_CLIENT_SECRET'],\n    refresh_token: refresh_token,\n    grant_type: 'refresh_token',\n  };\n  const resp = await axios.post('https://www.strava.com/api/v3/oauth/token', null, { params: params });\n\n  return {\n    access_token: resp.data.access_token,\n    refresh_token: resp.data.refresh_token,\n    expires_in: resp.data.expires_in\n  };\n}\n\nmodule.exports = {\n  getToken: getToken,\n  refreshToken: refreshToken,\n}\n"
  },
  {
    "path": "website/api/shared/validator.js",
    "content": "const Ajv = require('ajv/dist/2020');\nconst addFormats = require('ajv-formats');\nconst yaml = require('js-yaml');\nconst toml = require('@iarna/toml');\nconst fs = require('fs');\nconst path = require('path');\nconst axios = require('axios');\n\n// Configuration constants\nconst SCHEMA_GITHUB_URL = 'https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json';\nconst SCHEMA_FETCH_TIMEOUT = 10000;\n\n// Schema cache\nlet schema = null;\nlet schemaLoadPromise = null;\n\n/**\n * Load the schema from the local data folder, with GitHub fallback\n * @returns {Promise<Object>} The loaded schema\n */\nasync function loadSchema() {\n  // Return cached schema if available\n  if (schema) {\n    return schema;\n  }\n\n  // Return existing promise if schema is already being loaded\n  if (schemaLoadPromise) {\n    return schemaLoadPromise;\n  }\n\n  schemaLoadPromise = (async () => {\n    // Try loading from local data directory first\n    try {\n      const schemaPath = path.join(__dirname, '..', 'data', 'schema.json');\n      console.log('Attempting to load schema from:', schemaPath);\n\n      if (fs.existsSync(schemaPath)) {\n        const loadedSchema = JSON.parse(fs.readFileSync(schemaPath, 'utf8'));\n        console.log('Schema loaded successfully from local data folder');\n        schema = loadedSchema; // Set cache after successful load\n        return loadedSchema;\n      } else {\n        console.log('Local schema file not found, will fetch from GitHub');\n      }\n    } catch (error) {\n      console.log('Failed to load schema from local data folder:', error.message);\n    }\n\n    // Fallback to GitHub\n    try {\n      console.log('Fetching schema from GitHub');\n      const response = await axios.get(SCHEMA_GITHUB_URL, {\n        timeout: SCHEMA_FETCH_TIMEOUT\n      });\n      const loadedSchema = response.data;\n      console.log('Schema loaded successfully from GitHub');\n      schema = loadedSchema; // Set cache after successful load\n      return loadedSchema;\n    } catch (error) {\n      console.error('Failed to fetch schema from GitHub:', error.message);\n      throw new Error('Could not load schema from local data folder or GitHub');\n    }\n  })()\n    .finally(() => {\n      // Reset promise to allow retry on subsequent calls if this attempt failed\n      schemaLoadPromise = null;\n    });\n\n  return schemaLoadPromise;\n}\n\n// Initialize AJV with draft 2020-12 support (oh-my-posh schema uses draft 2020-12)\nconst ajv = new Ajv({\n  allErrors: true,\n  verbose: true,\n  strict: false,\n  validateFormats: true\n});\naddFormats(ajv);\n\n// Add custom format for color validation\najv.addFormat('color', {\n  validate: (data) => {\n    if (typeof data !== 'string') return false;\n    // This is a simple validation - the schema pattern handles the real validation\n    return true;\n  }\n});\n\n// Compile validator from schema\nlet validate = null;\nasync function getValidator() {\n  if (validate) {\n    return validate;\n  }\n\n  try {\n    const loadedSchema = await loadSchema();\n    if (!loadedSchema) {\n      throw new Error('Schema loading returned null');\n    }\n\n    validate = ajv.compile(loadedSchema);\n    return validate;\n  } catch (error) {\n    console.error('Failed to load or compile schema:', error);\n    throw error; // Propagate error instead of returning null\n  }\n}\n\n/**\n * Detect the format of the configuration content\n * @param {string} content - The configuration content\n * @returns {string} The detected format (json, yaml, or toml)\n */\nfunction detectFormat(content) {\n  const trimmed = content.trim();\n\n  // Try JSON first\n  if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n    return 'json';\n  }\n\n  // Check for TOML indicators\n  if (trimmed.match(/^\\[.*\\]$/m) || trimmed.match(/^[a-zA-Z_][a-zA-Z0-9_]*\\s*=/m)) {\n    return 'toml';\n  }\n\n  // Default to YAML (most permissive)\n  return 'yaml';\n}\n\n/**\n * Parse configuration content based on format\n * @param {string} content - The configuration content\n * @param {string} format - The format (json, yaml, toml, or auto)\n * @returns {Object} Parsed configuration object\n */\nfunction parseConfig(content, format) {\n  if (!content || typeof content !== 'string') {\n    throw new Error('Content must be a non-empty string');\n  }\n\n  const detectedFormat = format === 'auto' ? detectFormat(content) : format;\n\n  try {\n    switch (detectedFormat.toLowerCase()) {\n      case 'json':\n        return JSON.parse(content);\n\n      case 'yaml':\n      case 'yml':\n        return yaml.load(content);\n\n      case 'toml':\n        return toml.parse(content);\n\n      default:\n        throw new Error(`Unsupported format: ${detectedFormat}`);\n    }\n  } catch (error) {\n    throw new Error(`Failed to parse ${detectedFormat}: ${error.message}`);\n  }\n}\n\n/**\n * Format validation errors into human-readable messages\n * @param {Array} errors - AJV validation errors\n * @returns {Array} Formatted error messages\n */\nfunction formatErrors(errors) {\n  if (!errors || errors.length === 0) {\n    return [];\n  }\n\n  return errors.map(error => {\n    const path = error.instancePath || 'root';\n    let message = error.message;\n\n    // Enhance error messages based on error type\n    switch (error.keyword) {\n      case 'required':\n        message = `Missing required property: ${error.params.missingProperty}`;\n        break;\n      case 'enum':\n        message = `Value must be one of: ${error.params.allowedValues.join(', ')}`;\n        break;\n      case 'type':\n        message = `Must be of type ${error.params.type}`;\n        break;\n      case 'pattern':\n        message = `Must match pattern: ${error.params.pattern}`;\n        break;\n      case 'additionalProperties':\n        message = `Unexpected property: ${error.params.additionalProperty}`;\n        break;\n    }\n\n    return {\n      path: path,\n      message: message,\n      keyword: error.keyword,\n      params: error.params,\n      data: error.data\n    };\n  });\n}\n\n/**\n * Validate an oh-my-posh configuration\n * @param {string} content - The configuration content\n * @param {string} format - The format (json, yaml, toml, or auto)\n * @returns {Promise<Object>} Validation result\n */\nasync function validateConfig(content, format = 'auto') {\n  const result = {\n    valid: false,\n    errors: [],\n    warnings: [],\n    detectedFormat: null,\n    parsedConfig: null\n  };\n\n  try {\n    // Load and compile validator\n    const validator = await getValidator();\n\n    // Parse the configuration\n    const detectedFormat = format === 'auto' ? detectFormat(content) : format;\n    result.detectedFormat = detectedFormat;\n\n    const config = parseConfig(content, format);\n    result.parsedConfig = config;\n\n    // Validate against schema\n    const isValid = validator(config);\n    result.valid = isValid;\n\n    if (!isValid && validator.errors) {\n      result.errors = formatErrors(validator.errors);\n    }\n\n    // Add warnings for common issues\n    if (config && typeof config === 'object') {\n      // Check for deprecated version\n      if (config.version && config.version < 2) {\n        result.warnings.push({\n          path: 'version',\n          message: 'Using deprecated version format. Consider upgrading to version 2 or 3.',\n          type: 'deprecation'\n        });\n      }\n\n      // Check for missing $schema\n      if (!config.$schema) {\n        result.warnings.push({\n          path: '$schema',\n          message: 'Consider adding \"$schema\" property for better editor support.',\n          type: 'recommendation'\n        });\n      }\n    }\n\n  } catch (error) {\n    result.valid = false;\n\n    // Check if it's a schema loading error\n    if (error.message && error.message.includes('Could not load schema')) {\n      result.errors.push({\n        path: 'schema',\n        message: 'Schema could not be loaded. Validation is not available.',\n        keyword: 'schema',\n        params: {},\n        data: null\n      });\n    } else {\n      result.errors.push({\n        path: 'parse',\n        message: error.message,\n        keyword: 'parse',\n        params: {},\n        data: null\n      });\n    }\n  }\n\n  return result;\n}\n\n/**\n * Validate a segment configuration\n * @param {string} content - The segment content\n * @param {string} format - The format (json, yaml, toml, or auto)\n * @returns {Promise<Object>} Validation result\n */\nasync function validateSegment(content, format = 'auto') {\n  const result = {\n    valid: false,\n    errors: [],\n    warnings: [],\n    detectedFormat: null,\n    parsedSegment: null\n  };\n\n  try {\n    // Load and compile validator\n    const validator = await getValidator();\n\n    // Parse the segment\n    const detectedFormat = format === 'auto' ? detectFormat(content) : format;\n    result.detectedFormat = detectedFormat;\n\n    const segment = parseConfig(content, format);\n    result.parsedSegment = segment;\n\n    // Validate that it's an object\n    if (!segment || typeof segment !== 'object' || Array.isArray(segment)) {\n      result.errors.push({\n        path: 'root',\n        message: 'Segment must be a JSON object',\n        keyword: 'type',\n        params: {},\n        data: segment\n      });\n      return result;\n    }\n\n    // Check required fields\n    if (!segment.type) {\n      result.errors.push({\n        path: 'type',\n        message: 'Missing required property: type',\n        keyword: 'required',\n        params: { missingProperty: 'type' },\n        data: segment\n      });\n    }\n\n    if (!segment.style) {\n      result.errors.push({\n        path: 'style',\n        message: 'Missing required property: style',\n        keyword: 'required',\n        params: { missingProperty: 'style' },\n        data: segment\n      });\n    }\n\n    // If we already have errors, don't continue with schema validation\n    if (result.errors.length > 0) {\n      return result;\n    }\n\n    // Wrap segment in a minimal valid config for schema validation\n    const wrappedConfig = {\n      \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n      \"version\": 3,\n      \"blocks\": [\n        {\n          \"type\": \"prompt\",\n          \"alignment\": \"left\",\n          \"segments\": [segment]\n        }\n      ]\n    };\n\n    // Validate against schema\n    const isValid = validator(wrappedConfig);\n\n    if (!isValid && validator.errors) {\n      // Filter errors to only those related to the segment\n      // Errors will have paths like /blocks/0/segments/0/...\n      // Also filter out generic \"if/then\" schema errors as they're not helpful\n      const segmentErrors = validator.errors.filter(error => {\n        const isSegmentError = error.instancePath && error.instancePath.startsWith('/blocks/0/segments/0');\n        const isIfThenError = error.keyword === 'if';\n        return isSegmentError && !isIfThenError;\n      });\n\n      if (segmentErrors.length > 0) {\n        result.errors = formatErrors(segmentErrors.map(error => ({\n          ...error,\n          // Clean up the path to make it relative to the segment\n          instancePath: error.instancePath.replace('/blocks/0/segments/0', '')\n        })));\n      } else {\n        // All segments passed validation\n        result.valid = true;\n      }\n    } else {\n      result.valid = true;\n    }\n\n    // Add specific warnings for segment\n    if (segment.properties && segment.options) {\n      result.warnings.push({\n        path: 'properties',\n        message: 'Both \"properties\" and \"options\" are present. \"properties\" is deprecated, use \"options\" instead.',\n        type: 'deprecation'\n      });\n    } else if (segment.properties) {\n      result.warnings.push({\n        path: 'properties',\n        message: 'The \"properties\" field is deprecated. Please rename it to \"options\".',\n        type: 'deprecation'\n      });\n    }\n\n  } catch (error) {\n    result.valid = false;\n\n    // Check if it's a schema loading error\n    if (error.message && error.message.includes('Could not load schema')) {\n      result.errors.push({\n        path: 'schema',\n        message: 'Schema could not be loaded. Validation is not available.',\n        keyword: 'schema',\n        params: {},\n        data: null\n      });\n    } else {\n      result.errors.push({\n        path: 'parse',\n        message: error.message,\n        keyword: 'parse',\n        params: {},\n        data: null\n      });\n    }\n  }\n\n  return result;\n}\n\nmodule.exports = {\n  validateConfig,\n  validateSegment,\n  parseConfig,\n  detectFormat,\n  formatErrors\n};\n"
  },
  {
    "path": "website/api/shared/withings.js",
    "content": "const axios = require('axios');\n\nasync function getToken(code) {\n  const params = {\n    client_id: process.env['WITHINGS_CLIENT_ID'],\n    client_secret: process.env['WITHINGS_CLIENT_SECRET'],\n    code: code,\n    grant_type: 'authorization_code',\n    action: 'requesttoken',\n    redirect_uri: 'https://ohmyposh.dev/api/auth',\n  };\n\n  const resp = await axios.post('https://wbsapi.withings.net/v2/oauth2', null, { params: params });\n\n  if (resp.data.error) {\n    throw resp.data.error;\n  }\n\n  return {\n    access_token: resp.data.body.access_token,\n    refresh_token: resp.data.body.refresh_token,\n    expires_in: resp.data.body.expires_in\n  };\n}\n\nasync function refreshToken(refresh_token) {\n  const params = {\n    client_id: process.env['WITHINGS_CLIENT_ID'],\n    client_secret: process.env['WITHINGS_CLIENT_SECRET'],\n    refresh_token: refresh_token,\n    grant_type: 'refresh_token',\n    action: 'requesttoken',\n    redirect_uri: 'https://ohmyposh.dev/api/auth',\n  };\n  const resp = await axios.post('https://wbsapi.withings.net/v2/oauth2', null, { params: params });\n\n  return {\n    access_token: resp.data.body.access_token,\n    refresh_token: resp.data.body.refresh_token,\n    expires_in: resp.data.body.expires_in\n  };\n}\n\nmodule.exports = {\n  getToken: getToken,\n  refreshToken: refreshToken,\n}\n"
  },
  {
    "path": "website/api/test/validator.test.js",
    "content": "const { describe, it } = require('node:test');\nconst assert = require('node:assert');\nconst validator = require('../shared/validator.js');\n\n// Test fixtures\nconst fixtures = {\n  validConfig: `{\n    \"version\": 3,\n    \"blocks\": [\n      {\n        \"type\": \"prompt\",\n        \"alignment\": \"left\",\n        \"segments\": [\n          {\n            \"type\": \"path\",\n            \"style\": \"powerline\",\n            \"foreground\": \"#ffffff\",\n            \"background\": \"#0077c2\",\n            \"template\": \" {{ .Path }} \"\n          }\n        ]\n      }\n    ]\n  }`,\n\n  validYamlConfig: `\nversion: 3\nblocks:\n  - type: prompt\n    alignment: left\n    segments:\n      - type: path\n        style: powerline\n        foreground: \"#ffffff\"\n        background: \"#0077c2\"\n        template: \" {{ .Path }} \"\n  `,\n\n  invalidConfig: `{\n    \"version\": 3,\n    \"blocks\": []\n  }`,\n\n  validSegment: `{\n    \"type\": \"git\",\n    \"style\": \"powerline\",\n    \"foreground\": \"#ffffff\",\n    \"background\": \"#007acc\",\n    \"template\": \" {{ .HEAD }} \"\n  }`,\n\n  invalidSegmentNoType: `{\n    \"style\": \"powerline\"\n  }`,\n\n  invalidSegmentNoStyle: `{\n    \"type\": \"git\"\n  }`,\n\n  malformedJson: `{ \"invalid\": json }`\n};\n\ndescribe('oh-my-posh validator', () => {\n  describe('validateConfig', () => {\n    it('should validate a valid JSON config', async () => {\n      const result = await validator.validateConfig(fixtures.validConfig, 'json');\n      \n      assert.strictEqual(result.valid, true, 'Config should be valid');\n      assert.strictEqual(result.errors.length, 0, 'Should have no errors');\n      assert.strictEqual(result.detectedFormat, 'json');\n      assert.ok(result.parsedConfig, 'Should have parsed config');\n    });\n\n    it('should validate a valid YAML config', async () => {\n      const result = await validator.validateConfig(fixtures.validYamlConfig, 'yaml');\n      \n      assert.strictEqual(result.valid, true, 'Config should be valid');\n      assert.strictEqual(result.errors.length, 0, 'Should have no errors');\n      assert.strictEqual(result.detectedFormat, 'yaml');\n    });\n\n    it('should auto-detect format', async () => {\n      const result = await validator.validateConfig(fixtures.validConfig, 'auto');\n      \n      assert.strictEqual(result.valid, true);\n      assert.strictEqual(result.detectedFormat, 'json');\n    });\n\n    it('should handle malformed JSON', async () => {\n      const result = await validator.validateConfig(fixtures.malformedJson, 'json');\n      \n      assert.strictEqual(result.valid, false, 'Config should be invalid');\n      assert.ok(result.errors.length > 0, 'Should have parse errors');\n    });\n\n    it('should include parsed config in result', async () => {\n      const result = await validator.validateConfig(fixtures.validConfig, 'json');\n      \n      assert.ok(result.parsedConfig);\n      assert.strictEqual(result.parsedConfig.version, 3);\n      assert.ok(Array.isArray(result.parsedConfig.blocks));\n    });\n  });\n\n  describe('validateSegment', () => {\n    it('should validate a valid segment', async () => {\n      const result = await validator.validateSegment(fixtures.validSegment, 'json');\n      \n      assert.strictEqual(result.valid, true, 'Segment should be valid');\n      assert.strictEqual(result.errors.length, 0, 'Should have no errors');\n      assert.ok(result.parsedSegment, 'Should have parsed segment');\n    });\n\n    it('should reject segment missing type', async () => {\n      const result = await validator.validateSegment(fixtures.invalidSegmentNoType, 'json');\n      \n      assert.strictEqual(result.valid, false, 'Segment should be invalid');\n      assert.ok(result.errors.length > 0, 'Should have errors');\n      assert.ok(\n        result.errors.some(e => e.path === 'type'),\n        'Should have error about missing type'\n      );\n    });\n\n    it('should reject segment missing style', async () => {\n      const result = await validator.validateSegment(fixtures.invalidSegmentNoStyle, 'json');\n      \n      assert.strictEqual(result.valid, false, 'Segment should be invalid');\n      assert.ok(result.errors.length > 0, 'Should have errors');\n      assert.ok(\n        result.errors.some(e => e.path === 'style'),\n        'Should have error about missing style'\n      );\n    });\n\n    it('should include parsed segment in result', async () => {\n      const result = await validator.validateSegment(fixtures.validSegment, 'json');\n      \n      assert.ok(result.parsedSegment);\n      assert.strictEqual(result.parsedSegment.type, 'git');\n      assert.strictEqual(result.parsedSegment.style, 'powerline');\n    });\n  });\n\n  describe('parseConfig', () => {\n    it('should parse JSON', () => {\n      const result = validator.parseConfig(fixtures.validConfig, 'json');\n      \n      assert.ok(result);\n      assert.strictEqual(result.version, 3);\n    });\n\n    it('should parse YAML', () => {\n      const result = validator.parseConfig(fixtures.validYamlConfig, 'yaml');\n      \n      assert.ok(result);\n      assert.strictEqual(result.version, 3);\n    });\n\n    it('should throw on invalid content', () => {\n      assert.throws(\n        () => validator.parseConfig(fixtures.malformedJson, 'json'),\n        /Failed to parse/\n      );\n    });\n  });\n\n  describe('detectFormat', () => {\n    it('should detect JSON format', () => {\n      const format = validator.detectFormat('{ \"key\": \"value\" }');\n      assert.strictEqual(format, 'json');\n    });\n\n    it('should detect YAML format', () => {\n      const format = validator.detectFormat('key: value\\nother: thing');\n      assert.strictEqual(format, 'yaml');\n    });\n  });\n\n  describe('formatErrors', () => {\n    it('should format validation errors', () => {\n      const errors = [\n        {\n          instancePath: '/blocks/0',\n          message: 'must have required property \\'segments\\'',\n          keyword: 'required',\n          params: { missingProperty: 'segments' }\n        }\n      ];\n\n      const formatted = validator.formatErrors(errors);\n      \n      assert.ok(Array.isArray(formatted));\n      assert.strictEqual(formatted.length, 1);\n      assert.strictEqual(formatted[0].path, '/blocks/0');\n      assert.ok(formatted[0].message.includes('segments'));\n    });\n\n    it('should handle empty errors array', () => {\n      const formatted = validator.formatErrors([]);\n      assert.deepStrictEqual(formatted, []);\n    });\n  });\n});\n"
  },
  {
    "path": "website/blog/2022-03-20-whats-new-1.mdx",
    "content": "---\ntitle: \"What's new #1\"\ndescription: \"What's new #1\"\nslug: whats-new-1\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\ntags: [weekly, ohmyposh]\nhide_table_of_contents: false\n---\n\nWhat a week it’s been! Oh My Posh turned 6 years old and we dropped a ton of stuff!\n\n{/* truncate */}\n## Swag\n\nAfter seeing Scott Hanselman wear his oh my zsh shirt while we got to talk about\nOh My Posh on [Windows Wednesdays][windows-wednesdays], I got the sudden urge to expand his wardrobe.\n\n<iframe\n  className=\"youtube\"\n  src=\"https://www.youtube.com/embed/uO_F5W2LbSk\"\n  title=\"Windows Wednesdays: Oh My Posh\"\n  referrerPolicy=\"strict-origin-when-cross-origin\"\n  loading=\"lazy\"\n  allowFullScreen\n/>\n\nAnd so, we did. Got in touch with [Marc Duiker][marc] and we got to work. The result? A ton of new goodies.\nConsider this to be **the first artist series** for Oh My Posh, a way to also highlight some talented\npeople in the community. All profits go to the development of the project and artists also get a 20% royalty\nper item sold. If you know any interesting artists to work with for the next batch, be sure to let me know!\n\nSo, what are you waiting for? Get some!\n\n- [Shirts][shirts]\n- [Stickers][stickers]\n\n## Features\n\n### CLI interface\n\nSomething I've been sleeping on for a long time, Oh My Posh finally has a new CLI interface.\nStarting out I had no experience in Go, nor any idea on how to create a proper CLI interface.\nOver the years the interface grew, but **_not in a very sustainable way_**, it was a chain of if statements\nwhich was a bit of a pain to support.\n\nYou can now interact with Oh My Posh via an interface powered by [Cobra][cobra]. Not only does this\nbring maintainability and extensibility, it at once introduces a few added features.\n\n#### Init\n\nIf you paid attention to the evolution of the `init` functionality which automatically supercharges\nyour prompt, you might have noticed I was always trying to make it easier for anyone to get started. When working on the\n[shirts][shirts] with Marc, it hit me we didn't really have an identifiable prompt as a first time\nexperience. So, as of [7.42.0][7.42.0] Oh My Posh can initialize your prompt without specifying the\n`--config` flag. Because we have no way to know how you installed Oh My Posh, and if you have themes\ninstalled locally, we download the default theme, cache and use it to get you up and running right there.\n\nWhen using PowerShell for example, this is all it takes from now on:\n\n```powershell\noh-my-posh init pwsh | Invoke-Expression\n```\n\n:::info remote config\nIn case you missed it, as I haven't really done these updates before, you can also use\na remote config file nowadays. Also **triggered by Scott Hanselman** who uses multiple devices\nbut still wants the same, seamless experience everywhere. I'm sure he's not alone 😄.\n:::\n\n#### Export config\n\nWhile this functionality was already present, you can now also save the current config to a new\nfile in the format of your choice. Combining that with the new initialization above, new users can\nright away save the default config elsewhere and tweak it to make it their own.\n\n```powershell\n\noh-my-posh config export --output=~/.mytheme.omp.json\n\n```\n\n#### Edit\n\nPutting things together, all we needed additionally was a way to edit the config.\n\n```powershell\n\noh-my-posh config edit\n\n```\n\nAlmost feels natural right?\n\n### RRRRRRR Matey!\n\nThanks to [Jed Willick][jed], who's already been on a roll for a while adding segments to Oh My Posh,\nwe now have a [segment][r-segment] for [R][r] 🏴‍☠️. Read all about it [here][r-segment].\n\n## Bug fixes\n\nObviously, nothing is perfect. But we aim to be! The following issues have been found and fixed:\n\n- We now display the right distro name in WSL\n- The poshgit prompt is now disabled when using Oh My Posh\n- Terminal titles are stripped from ANSI escape sequences, otherwise they are not displayed correctly\n- The config file now also works with the `.yml` extension and not only `.yaml`\n\nThat's it for this week, I'll try to keep this up 🤞🏻.\n\n_Keep that prompt posh everyone!_\n\n[windows-wednesdays]: https://devblogs.microsoft.com/commandline/windows-wednesday/\n[marc]: https://twitter.com/marcduiker\n[shirts]: https://swag.ohmyposh.dev\n[stickers]: https://pimpyourowndevice.com/community/\n[cobra]: https://github.com/spf13/cobra\n[7.42.0]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/tag/v7.42.0\n[jed]: https://github.com/jedwillick\n[r-segment]: https://ohmyposh.dev/docs/r\n[r]: https://www.r-project.org/about.html\n"
  },
  {
    "path": "website/blog/2022-03-27-whats-new-2.md",
    "content": "---\ntitle: \"What's new #2\"\ndescription: \"What's new #2\"\nslug: whats-new-2\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\ntags: [weekly, ohmyposh]\nhide_table_of_contents: false\n---\n\nWouldn't have imagined doing part two in a week's time, but here we are again!\n\n<!--truncate-->\n## Features\n\n### CLI interface (also #2)\n\nIn the [previous post][blog-1] I highlighted some changes in the CLI interface. Turns out I could make it\neven more straightforward. As Oh My Posh is a prompt generating utility, the `prompt` command\ndoesn't make sense as that's implied. It has been removed, although it **will keep working** to\nnot break existing functionality on upgrade.\n\n#### Init\n\nThe following initialization:\n\n```powershell\noh-my-posh prompt init pwsh | Invoke-Expression\n```\n\nnow becomes:\n\n```powershell\noh-my-posh init pwsh | Invoke-Expression\n```\n\n#### Debug\n\nTo debug Oh My Posh, you can simply use the `debug` command. It's smart enough to know your config\nso you don't have to specify the `--config` option.\n\n```powershell\noh-my-posh debug\n```\n\n### Fish shell\n\nWe already supported [fish shell][fish] for a while, but we stepped up the game. I started using fish\nas my primary shell, so obviously it couldn't stay behind. I suggest you also have\na go at it, it's a very enjoyable experience.\n\nBut OK, what changed? We now support the following out-of-the-box:\n\n- [right prompt][right]\n- [transient prompt][transient]\n- [tooltips][tooltips]\n\nIt seems there's **_no support (yet) for a secondary prompt in fish_**, once that's available we can easily add that too.\nTo enjoy all of this, upgrade to the latest and initialize fish by adding the following line to `~/.config/fish/config.fish`:\n\n```bash\noh-my-posh init fish | source\n```\n\n### Transient prompt\n\nSpeaking of [transient][transient], it learned some new tricks. First, you can now use the `.Code` property to work with\nthe last command's error code (if any) in the template. This can for example be used to color the transient prompt\ndifferently when the last command failed. That did imply we also needed support for color [templates][color-templates],\nas that wasn't possible just yet. Say no more, we now have a [transient prompt][transient] that supports color templates.\n\n```json\n\"transient_prompt\": {\n    \"background\": \"p:yellow\",\n    \"background_templates\": [\n      \"{{ if gt .Code 0 }}p:red{{ end }}\"\n    ],\n    \"foreground\": \"p:black\",\n    \"foreground_templates\": [\n      \"{{ if gt .Code 0 }}p:white{{ end }}\"\n    ],\n    \"template\": \"<background,transparent>\\ue0b6</> {{ .Folder }} <background,transparent>\\ue0b0</><,transparent> </>\"\n}\n```\n\nWhich produces the following result:\n\n![Terminal](../static/img/transient-color.png)\n\n### Config version 2\n\nRemember we did a migration to config version 1 in the beginning of the year? Well, we did a migration to version 2.\nLooking at Oh My Posh's architecture, the different prompts (transient, secondary, ...) were moving closer to the model\nused by segments. The only difference was that `template` wasn't a property, but a field of those prompts. As **all segments\nnow have template support**, it was a no-brainer to align both models and do a migration to config version 2 so nobody\nwould have any manual work in the process.\n\nThe following segment definition:\n\n```json\n{\n  \"background\": \"#9A348E\",\n  \"foreground\": \"#ffffff\",\n  \"leading_diamond\": \"\\ue0b6\",\n  \"properties\": {\n    \"template\": \"{{ .UserName }} \"\n  },\n  \"style\": \"diamond\",\n  \"type\": \"session\"\n}\n```\n\nWill now be migrated to this for version 2:\n\n```json\n{\n  \"background\": \"#9A348E\",\n  \"foreground\": \"#ffffff\",\n  \"leading_diamond\": \"\\ue0b6\",\n  \"style\": \"diamond\",\n  \"template\": \"{{ .UserName }} \",\n  \"type\": \"session\"\n}\n```\n\n## Go 1.18\n\nNot something that impacts the end user directly, but maybe interesting to know is that Oh My Posh is now\nusing [go 1.18][go1.18] by default. This brings obvious language improvements and a few new features we can play with.\nThe most notable is generics, but it doesn't seem like we can benefit just yet as it's not yet supported\nfor methods, and that's the main use-case for us.\n\nNonetheless, it's good to stay up-to-date, if you notice any quirks though, be sure to let us know!\n\nThat's it for this week, see you for the next one 🤞🏻\n\n_Keep that prompt posh everyone!_\n\n[blog-1]: /blog/whats-new-1\n[fish]: https://fishshell.com/\n[right]: /docs/configuration/block#type\n[transient]: /docs/configuration/transient\n[tooltips]: /docs/configuration/tooltips\n[color-templates]: /docs/configuration/colors#color-templates\n[go1.18]: https://tip.golang.org/doc/go1.18\n"
  },
  {
    "path": "website/blog/2022-03-28-idiots-everywhere.md",
    "content": "---\ntitle: \"What idiot wrote this code?\"\ndescription: \"It was me...\"\nslug: idiots-everywhere\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\ntags: [weekly, ohmyposh]\nhide_table_of_contents: false\n---\n\nIt finally happened, **I introduced a bug** that only appears in 1 use case and it can't be resolved as it's the result\nof using an old and new version of Oh My Posh at the same time. Who does that you might ask? Well, it can be because you're\nusing WSL on Windows, or VM’s on any system while sharing the same configuration cross installation.\nNot the main use-case, but also not exotic either.\n\n<!-- truncate -->\n\n## What happened?\n\nIn the beginning of the year, after what has been quite the struggle, I was finally able to deliver **the most important\narchitectural update** since the introduction of the rewrite in Go. Because of this, a migration of old configs was needed\nso that no end user would have to go through the ordeal of figuring out what to map where, it's a very logical process\nand obviously computers are better at that.\n\nTo facilitate this, I added a config property called `version` which can be incremented when the configuration evolves\nand triggers an automatic migration when necessary. The logic to identify the need for migration is as follows:\n\n```go\nif !env.Flags().Migrate && cfg.Version != configVersion {\n    cfg.BackupAndMigrate(env)\n}\n```\n\nIf you're observant, you might already spot the issue now that you know the use-case. For those of us who like to read\nand not think, the result is rather straightforward as it will always run the migration, either when forced (because you\ncan use `oh-my-posh config migrate` manually), or when the current config version doesn't match the required config\nversion. _Simple, right?_ And this works according to expectations when updating Oh My Posh. The problem starts when you\nhave a shared config, and use multiple versions of Oh My Posh on the same machine.\n\nImagine working using multiple shells, one is WSL Ubuntu with a version of Oh My Posh that's still on version 1\n(**S1**). One day, you update PowerShell in Windows to use the latest greatest, using version 2 (**S2**). Starting S2,\n**it automatically migrates the config to version 2**, moving the `template` property to the segment's model.\n\nIn practice, the following version 1 config:\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 1,\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#9A348E\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"properties\": {\n            // highlight-next-line\n            \"template\": \"{{ .UserName }} \"\n          },\n          \"style\": \"diamond\",\n          \"type\": \"session\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nIs migrated to:\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 2,\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#9A348E\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          // highlight-next-line\n          \"template\": \"{{ .UserName }} \",\n          \"style\": \"diamond\",\n          \"type\": \"session\"\n        }\n      ]\n    }\n  ]\n}\n```\n\nAwesome, no user interaction at all and _everything works as designed_. However, you now want to do something using S1,\nand due to the logic, Oh My Posh sees that `2 != 1` and **the migration is triggered for version 1**. The migration as such\nis non-breaking, but Oh My Posh doesn't know the `template` property on `segment` in this case. The end result of our\nconfig above is rather annoying as we're now left with this:\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 1,\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"background\": \"#9A348E\",\n          \"foreground\": \"#ffffff\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"style\": \"diamond\",\n          \"type\": \"session\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n😱 the template is gone! Nothing to worry about just yet, Oh My Posh will use the default template so you will still see\na prompt, and the migration also _creates a backup_ of your previously correct version 2 config. Up to this point you\ncan still revert, it's unfortunate, but your local tweaks are still available. If you happen to continue working in S2 at\nthis point however, it will once again trigger the migration to version 2 and **overwrite your backup with the faulty\nversion 1 config**.\n\nWhile the fix for this issue in code is trivial, it's impossible to push that to older versions. People will upgrade\nto the most recent version, and in this specific setup, this is potentially breaking. **The advice is to upgrade all versions\nat once**, so you only migrate once and there's no \"old\" version of Oh My Posh left to trigger this unwanted side-effect.\n\nThe actual fix for the issue can be found in [7.52.1][fix-version], but due to obvious reasons, it will only work\ngoing from version 2 to any new config version in the future.\n\n```go\nif !env.Flags().Migrate && cfg.Version < configVersion {\n    cfg.BackupAndMigrate(env)\n}\n```\n\nWhile I try hard to come up with every possible edge case when validating this logic, sometimes things slip through.\nEven when looking at this one **I find it challenging not having considered that case**, but it still happened. The\ngood news? It won't happen again 😅\n\n[fix-version]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/tag/v7.52.1\n"
  },
  {
    "path": "website/blog/2022-05-19-whats-new-3.md",
    "content": "---\ntitle: \"What's new #3\"\ndescription: \"What's new #3\"\nslug: whats-new-3\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\ntags: [weekly, ohmyposh]\nhide_table_of_contents: false\n---\n\nSo long, old friend!\n\n<!--truncate-->\n## PowerShell module\n\nIn the beginning, all we had was the [PowerShell Module][module]. It's the _origin of Oh My Posh_\nand has remained available ever since, even with the move to Go. With that evolution however,\nits advantages have been greatly reduced. In fact, it even introduced [additional hurdles][hurdles] along\nthe way.\n\nAs of March, the module no longer offers new functionality and displays a warning message. Have a look\nat the [migration page][migration] for a guide on how to migrate from the module to other means of\ninstallation. It only takes a minute.\n\n## Giveaway\n\nA fews weeks ago I started a [giveaway][giveaway] to celebrate the 6 year anniversary of Oh My Posh.\nBut then I went on holiday, and didn't follow up to announce the winner. So without further ado,\n**congratulations to [@samerde][samerde]** for getting picked by a random online random picker and\nwinning the giveaway!\n\n## Features\n\nIt's been a while, so you might want to hang tight 😅\n\n### PowerShell UTF-8\n\nIn the early days, Oh My Posh was forcibly setting PowerShell to UTF-8 due to issues with fonts and paths.\nHowever, it turned out that wasn't really necessary. A new way of invocation was introduced, which removes\nthe need to set this shell wide and **avoids unwanted side effects**. This can however still break path when\nfor example your `--config` path contains a non-ascii character. Can't win them all I guess. In that case,\nset the shell to UTF-8 in the scope of initializing Oh My Posh.\n\n```powershell\n$previousOutputEncoding = [Console]::OutputEncoding\n[Console]::OutputEncoding = [Text.Encoding]::UTF8\ntry {\n    oh-my-posh init pwsh --config ~/custom.omp.json | Invoke-Expression\n} finally {\n    [Console]::OutputEncoding = $previousOutputEncoding\n}\n```\n\n### Nu shell\n\nIf you haven't seen [Nu shell][nu] yet, it's a new kid on the block. Oh My Posh now supports it just\nlike we support any other popular shell (bash, zsh, fish, etc). This means we can keep adding functionality\nwithout the need for user interaction apart from updating Oh My Posh.\n\n### Accordion\n\nEver wanted to have a `powerline` segment to display collapsed when disabled? Now you can!\nUse the `accordion` style to display a segment in a collapsible state.\n\n![Accordion prompt](/img/accordeon.png)\n\n### Project\n\nThings just keep growing. The [project][project] segment now supports the following project definitions:\n\n- [cargo][cargo]\n- [poetry][poetry]\n- [php][php]\n- [nuspec][nuspec]\n\n### Shell\n\nIf you work with multiple shell versions, this one's for you. You can now use the `.Version` property\nin the [shell][shell] segment to distinct between versions:\n\n```json\n\"template\": \" in {{ .Name }} {{ .Version }} \"\n```\n\n### Git\n\nThe [git][git] segment learned a new trick to make your life easier (or faster). Before we hardcoded the\nuntracked files mode to `normal`. However, on larger repo's this can get rather cumbersome, so we now allow\nyou to **override this per repo**.\n\n```json\n\"untracked_modes\": {\n  \"/Users/user/Projects/oh-my-posh/\": \"no\"\n}\n```\n\nThe available options are listed in the [git documentation][git-status], use them as you see fit!\n\n### Cross segment template properties\n\nWait, what? Yes, you read that right. Oh My Posh now supports **cross segment template properties**.\nThis means you can use one segment's properties in another segment's template. How? Oh My Posh\nexposes the `.Segments` property which contains all segment's properties in a map. To make use\nof another segment's data, use `{{ .Segments.Segment }}` in your template where `.Segment`\nis the name of the segment you want to use with the first letter uppercased.\n\nIf you want to for example use the [git][git] segment's `.UpstreamGone` property in the [exit][exit] segment, you can\ndo so like this:\n\n```json\n\"template\": \" {{ if .Segments.Git.UpstreamGone }}\\uf7d3{{ else if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} \"\n```\n\n:::caution\nFor this to work, the segment you refer to needs to be in your config. The above example won't work if\nyour config does not contain a git segment as Oh My Posh only populates the properties when it needs to.\n:::\n\n### Other\n\n- `oh-my-posh debug` now measures the run time correctly and can log startup logic\n- The language segments can now distinct between files and folders\n- The [python][python] segment now supports pyenv `.python-version` files\n- The `init` command has a new switch called `--strict` which no longer resolves the executable\n- The [battery][battery] segment can now display all relevant states on macOS\n- The [dotnet][dotnet] segment now supports `.slnf` files\n- A [new][iterm] segment to display iTerm shell integration prompt marks\n- The [memory][memory] segment can now display available memory\n- The [path][path] segment now has a `.Writable` property, indicating if the current user\ncan write to the current folder\n\n### Fixes\n\n- The [git][git] segment can now handle repo's with `--separate-git-dir`\n- Hyperlinks are correctly measured (which should display the right aligned prompt correctly)\n- Prompt escape sequences are correctly escaped, this avoids unwanted visual side effects\n- Spotify now works correctly on Windows for non-English systems\n- Parallel logic to make things fast no longer randomly crashes on Windows\n- Upstream gone logic for git was broken, and has been fixed\n- PSReadLine in PowerShell now receives the correct amount of prompt lines (`Set-PSReadlineOption -ExtraPromptLineCount`),\nthis fixes weird behaviour when using a transient prompt when your config results in a multiline prompt\n- The [winget][winget] installer now adds `PATH` entries correctly, regardless of the installation mode\n\nThat's it for this time, see you for the next one 🤞🏻\n\n_Keep that prompt posh everyone!_\n\n[module]: https://www.powershellgallery.com/packages/oh-my-posh/7.85.2\n[hurdles]: /docs/migrating#problem-statement\n[migration]: /docs/migrating\n[giveaway]: https://twitter.com/jandedobbeleer/status/1511031115569639428?s=20&t=5aZbBZxGXbCBmc-R4WAdIQ\n[samerde]: https://twitter.com/samerde\n[project]: /docs/segments/system/project\n[git]: /docs/segments/scm/git\n[python]: /docs/segments/languages/python\n[shell]: /docs/segments/system/shell\n[nu]: https://www.nushell.sh\n[git-status]: https://git-scm.com/docs/git-status#Documentation/git-status.txt--ultmodegt\n[cargo]: https://crates.io\n[poetry]: https://python-poetry.org\n[php]: https://getcomposer.org\n[nuspec]: https://docs.microsoft.com/en-us/nuget/reference/nuspec\n[battery]: /docs/segments/system/battery\n[winget]: https://docs.microsoft.com/en-us/windows/package-manager/winget/\n[dotnet]: /docs/segments/languages/dotnet\n[iterm]: /docs/configuration/general#settings\n[memory]: /docs/segments/system/sysinfo#properties\n[exit]: /docs/segments/system/status\n[path]: /docs/segments/system/path\n"
  },
  {
    "path": "website/blog/2024-07-22-bash-rprompt.md",
    "content": "---\ntitle: \"Deprecating the bash rprompt\"\ndescription: \"Deprecating the bash rprompt\"\nslug: deprecating-bash-rprompt\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\ntags: [breaking, ohmyposh]\nhide_table_of_contents: false\n---\n\nAfter careful consideration, it was decided to remove support for the [`rprompt`][rprompt] in bash. If you are\ninterested in the reasons behind this decision, please read on.\n\n<!--truncate-->\n## Context\n\n[`rprompt`][rprompt] is a feature that allows you to display a prompt at the right side of the terminal, on\nthe same line as your cursor. This feature is available natively on a lot of shells, but not on bash.\nTo work around this limitation, Oh My Posh has a **custom implementation** we use for both bash and PowerShell.\n\n## History\n\n### First implementation\n\nThere were two evolutions of bash' custom [`rprompt`][rprompt] in Oh My Posh. The first one printed the [`rprompt`][rprompt]\ntogether with the primany prompt in the `PS1` variable, so we only need one CLI call to visualize the prompt.\n\nThe challenge is that, as the [`rprompt`][rprompt] is printed together with the primary prompt, we need to make sure\nbash' readline can interpret the prompt correctly. In bash, every character that isn't a printable character,\nlike color codes, needs to be wrapped in `\\[` and `\\]`. This is necessary to make sure bash can **calculate the length**\nof the prompt and ultimately **position the cursor** correctly.\n\nIt turned out that for [`rprompt`][rprompt], this _needed to be done differently_. The [`rprompt`][rprompt] is printed\nafter what bash interprets as the end of the prompt. We found out that we need to wrap the entire [`rprompt`][rprompt] in\n`\\[` and `\\]`, and not escape individual non-printable characters.\n\nWe did that for a while, but apparently this approach was **not very robust**. It was easy to break readline's\ncursor position calculation, and it was hard to debug. The behaviour of this was also different cross platform,\nso we had to go back to the drawing board.\n\n### Second implementation\n\nThe second implementation of the [`rprompt`][rprompt] was a lot more robust. We decided to print the [`rprompt`][rprompt]\nin a separate CLI call, so we could control the output more easily. It leveraged the use of the `PROMPT_COMMAND`\nvariable in bash, which is a hook that is executed before the prompt is printed. We would first print the\n[`rprompt`][rprompt] in the `PROMPT_COMMAND`,\nand then set the primary prompt in the `PS1` variable so bash would not bother about the [`rprompt`][rprompt] being there.\n\nThis approach was a lot **cleaner from an achitectural point of view**, but it came with its own challenges.\nThe most obvious one is needing two CLI calls to print the prompt, which made rendering a bit slower than the first implementation.\n\nAdditionally, as we print before `PS1` is evaluated, we noticed the following issues along the way:\n\n1. when the output of the previous command didn't end with a newline, the [`rprompt`][rprompt] would be printed on the\n  same line as the output of the previous command\n2. when the prompt was at the bottom of the terminal buffer, the [`rprompt`][rprompt] would be printed on the same line\n  as the prompt, which would break the prompt\n3. depending on the platform, it would still break command history navigation\n4. it required different logic for multiline prompts as we print before `PS1` and need to reposition the cursor correctly\n\nOf these issues, **only bullet 4 could be fixed**. Everything else was outside of our control.\n\n## Conclusion\n\nOh My Posh is a tool that needs to be easy to use, maintain and be 100% reliable. One of the core principles of\nOh My Posh is that it should **never break the shell**. The [`rprompt`][rprompt] feature in bash has never been reliable\nenough, and it was _hard to debug_ when it broke.\nI spent countless hours debugging issues with the [`rprompt`][rprompt] in bash, but it's **time to move on**. If you\nwant to use the [`rprompt`][rprompt] feature, I would recommend using a shell that supports it natively, like\n[nushell], [zsh] or [fish].\n\n## What about Powershell?\n\nThe [`rprompt`][rprompt] feature in PowerShell is **100% reliable**, even if it's not natively supported. PowerShell doesn't\nhave the same challenges calculating the actual prompt width like bash, there's _no need to escape anything_.\nWe can use the first implementation mentioned above, and it works like a charm.\n\n[rprompt]: /docs/configuration/block#type\n[nushell]: https://www.nushell.sh/\n[zsh]: https://www.zsh.org/\n[fish]: https://fishshell.com/\n"
  },
  {
    "path": "website/blog/2025-12-28-oh-my-posh-claude-code-integration.md",
    "content": "---\ndate: 2025-12-28\ndescription: Oh My Posh now integrates with Claude Code's statusline feature to bring beautiful, customizable AI session information right into your terminal prompt.\ntags:\n- claude\n- ai\n- terminal\n- prompt\n- statusline\n- integration\n- customization\ntitle: \"Oh My Posh Meets Claude Code: AI-Powered Terminal Prompts\"\nslug: oh-my-posh-claude-code-integration\nauthors:\n- name: Jan De Dobbeleer\n  title: Maintainer\n  url: https://github.com/jandedobbeleer\n  image_url: https://avatars.githubusercontent.com/u/2492783?v=4\n---\n\nTerminal customization just got a lot smarter. Oh My Posh now integrates with [Claude Code](https://code.claude.com/)\nthrough its [`statusline` functionality](https://code.claude.com/docs/en/statusline), bringing real-time AI session\ninformation  and development context directly into your Claude Code prompt.\nThis isn't just another segment: it's a bridge between your\ndevelopment workflow and AI-powered coding assistance.\n\n![Claude Code](/img/claude.png)\n\n<!--truncate-->\n## What is Claude Code's statusline?\n\nClaude Code's `statusline` feature allows you to create custom status displays that appear at the bottom of\nthe Claude Code interface, similar to how terminal prompts work in shells. The `statusline` receives rich JSON\ndata about your current AI session via stdin, including:\n\n- **Model information**: Which Claude model you're using (Claude Sonnet, Claude Opus, etc.)\n- **Token usage**: Input/output tokens, context window utilization, and usage percentages\n- **Cost tracking**: Real-time cost calculations and session duration\n- **Workspace context**: Current and project directories\n- **Session metadata**: Unique session IDs and version information\n\nThe `statusline` updates automatically when conversation messages change (throttled to every 300ms max), and\nyour command's stdout becomes the status display with full ANSI color support.\n\n### Setting Up the Integration\n\nConfiguration is straightforward. Add this to your Claude Code settings:\n\n```json title=\"~/.claude/settings.json\"\n{\n  \"statusLine\": {\n    \"type\": \"command\",\n    \"command\": \"oh-my-posh claude\",\n    \"padding\": 0\n  }\n}\n```\n\nThat's it! Oh My Posh will automatically detect when Claude Code provides session data and display the\nrelevant information in your prompt.\n\nIt's important to note that the `claude` CLI command operates differently from your regular prompt\nconfiguration. When used as a `statusline` command, Oh My Posh runs in a special mode that's completely separate\nfrom your standard terminal prompt. This means you'll likely want to create a dedicated, minimal configuration\nspecifically for Claude Code that focuses on displaying AI session information rather than your usual prompt\nelements.\n\n### Custom configuration\n\nBy default, the `oh-my-posh claude` command provides a built-in `statusline` that shows your current working\ndirectory, git context, active model name, and context window usage as a visual gauge. To customize this\ndisplay, use the `--config` flag to specify your own theme configuration file that includes a custom claude\nsegment tailored to your preferences.\n\n```json title=\"~/.claude/settings.json\"\n{\n  \"statusLine\": {\n    \"type\": \"command\",\n    \"command\": \"oh-my-posh claude --config ~/.claude.omp.json\",\n    \"padding\": 0\n  }\n}\n```\n\nJust make sure the configuration also leverages the data available in the `claude` segment to visualize the stats you\ncare about. As this isn't like a regular prompt integration, keep the `statusline` a single line and use left and right\naligned prompt blocks to play with.\n\n```json title=\"~/.claude.omp.json\"\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"palette\": {\n    \"black\": \"#262B44\",\n    \"blue\": \"#4B95E9\",\n    \"green\": \"#59C9A5\",\n    \"orange\": \"#F07623\",\n    \"red\": \"#D81E5B\",\n    \"sapling\": \"#a6d189\",\n    \"white\": \"#E0DEF4\",\n    \"yellow\": \"#F3AE35\"\n  },\n  \"accent_color\": \"32\",\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"options\": {\n            \"dir_length\": 3,\n            \"folder_separator_icon\": \"\\ue0bb\",\n            \"style\": \"fish\"\n          },\n          \"template\": \"{{ if .Segments.Git.Dir }} \\uf1d2 <i><b>{{ .Segments.Git.RepoName }}{{ if .Segments.Git.IsWorkTree }} \\ue21c{{ end }}</b></i>{{ $rel :=  .Segments.Git.RelativeDir }}{{ if $rel }} \\ueaf7 {{ .Format $rel }}{{ end }}{{ else }} \\uea83 {{ path .Path .Location }}{{ end }} \",\n          \"foreground\": \"p:white\",\n          \"leading_diamond\": \"\\ue0b6\",\n          \"background\": \"p:orange\",\n          \"type\": \"path\",\n          \"style\": \"diamond\"\n        },\n        {\n          \"options\": {\n            \"branch_icon\": \"\\ue0a0\",\n            \"fetch_status\": true\n          },\n          \"template\": \" {{ if .UpstreamURL }}{{ url .UpstreamIcon .UpstreamURL }} {{ end }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ nospace .Working.String }}{{ end }}{{ if .Staging.Changed }} \\uf046 {{ .Staging.String }}{{ end }} \",\n          \"foreground\": \"p:black\",\n          \"leading_diamond\": \"<parentBackground,background>\\ue0b0</>\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"background\": \"p:green\",\n          \"type\": \"git\",\n          \"style\": \"diamond\",\n          \"foreground_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}p:black{{ end }}\",\n            \"{{ if or (gt .Ahead 0) (gt .Behind 0) }}p:white{{ end }}\"\n          ],\n          \"background_templates\": [\n            \"{{ if or (.Working.Changed) (.Staging.Changed) }}p:yellow{{ end }}\",\n            \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:red{{ end }}\",\n            \"{{ if gt .Ahead 0 }}#49416D{{ end }}\",\n            \"{{ if gt .Behind 0 }}#7A306C{{ end }}\"\n          ]\n        }\n      ]\n    },\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"right\",\n      \"segments\": [\n        {\n          \"leading_diamond\": \"\\ue0b6\",\n          \"template\": \" \\udb82\\udfc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.GaugeUsed }} \",\n          \"foreground\": \"p:white\",\n          \"background\": \"accent\",\n          \"type\": \"claude\",\n          \"style\": \"diamond\"\n        },\n        {\n          \"options\": {\n            \"charged_icon\": \"\\ue22f \",\n            \"charging_icon\": \"\\ue234 \",\n            \"discharging_icon\": \"\\ue231 \"\n          },\n          \"cache\": {\n            \"duration\": \"10m\",\n            \"strategy\": \"session\"\n          },\n          \"leading_diamond\": \"<background,parentBackground>\\ue0b2</>\",\n          \"trailing_diamond\": \"\\ue0b4\",\n          \"template\": \"{{ if not .Error }} {{ .Icon }}{{ .Percentage }}%{{ end }}\",\n          \"foreground\": \"#111111\",\n          \"background\": \"accent\",\n          \"type\": \"battery\",\n          \"style\": \"diamond\",\n          \"background_templates\": [\n            \"{{if eq \\\"Discharging\\\" .State.String}}p:orange{{end}}\",\n            \"{{if eq \\\"Full\\\" .State.String}}p:green{{end}}\"\n          ]\n        }\n      ]\n    }\n  ],\n  \"version\": 4\n}\n```\n\n## The Claude Code segment\n\nOh My Posh's new `claude` segment taps into this `statusline` data to bring AI session awareness directly\ninto your terminal prompt. When you use the `oh-my-posh claude` command as your `statusline` command in Claude\nCode, you get access to a wealth of session information that can be displayed in your prompt without needing\nto know the technical details.\n\n### Example Configuration\n\nHere's a sample configuration that shows the model name and context usage:\n\n```json\n{\n  \"type\": \"claude\",\n  \"style\": \"diamond\",\n  \"leading_diamond\": \"\\ue0b6\",\n  \"trailing_diamond\": \"\\ue0b4\",\n  \"foreground\": \"#FFFFFF\",\n  \"background\": \"#FF6B35\",\n  \"template\": \" \\udb82\\udfc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.Gauge }} \"\n}\n```\n\nThis displays something like: ` 🤖 Claude 4.5 Sonnet  ▰▰▰▱▱ `\n\nThe gauge provides instant visual feedback on how much of your context window you've consumed, which is\ncrucial for managing long coding sessions.\n\n## The Technical Details\n\nUnder the hood, Oh My Posh reads the rich JSON session data that Claude Code provides via stdin when used\nas a `statusline` command. The segment only activates when Claude Code session data is available, so there's no\nperformance impact when you're not using Claude Code.\n\n## Getting Started\n\nIf you're already using Oh My Posh, adding Claude Code integration is as simple as:\n\n1. Install Claude Code if you haven't already\n2. Add the `statusline` configuration to your Claude Code settings\n3. Optionally create your own configuration including the `claude` segment\n4. Start a Claude Code session and watch your prompt come alive\n\nFor detailed configuration options and all available properties, check out the [complete Claude segment documentation](https://ohmyposh.dev/docs/segments/cli/claude).\n\n## What's Next?\n\nThis integration opens up exciting possibilities. Imagine prompts that:\n\n- Change color based on token usage percentage\n- Show different icons for different AI models\n- Display cost warnings when sessions get expensive\n- Integrate with any other segment to show additional development context\n\nThe foundation is there, and now it's up to the community to build amazing configurations that make\nAI-powered development even more seamless.\n"
  },
  {
    "path": "website/docs/advanced/mcp-server.mdx",
    "content": "---\nid: mcp-server\ntitle: MCP Server\nsidebar_label: MCP Server\n---\n\n## What is the Oh My Posh MCP Server?\n\nThe Oh My Posh MCP (Model Context Protocol) Server is a validation service that allows you to validate your oh-my-posh\ntheme configurations against the official JSON schema. It supports JSON, YAML, and TOML formats and provides detailed\nerror reporting to help you create valid configurations.\n\n## Features\n\n- **Multi-format Support**: Validates JSON, YAML, and TOML configurations\n- **Detailed Error Reporting**: Get precise validation errors with JSON paths\n- **Format Auto-detection**: Automatically detects the format of your configuration\n- **Warnings & Recommendations**: Receive best practice suggestions and deprecation warnings\n- **Standards-based**: Uses the official oh-my-posh JSON schema\n- **Remote Access**: No installation required - access via HTTPS\n\n## Usage\n\n### With MCP Clients\n\nConfigure your MCP-compatible client (like Claude Desktop, Cline, or other AI assistants) to use the validator:\n\n```json\n{\n  \"mcpServers\": {\n    \"oh-my-posh-validator\": {\n      \"url\": \"https://ohmyposh.dev/api/mcp\",\n      \"transport\": \"http\"\n    }\n  }\n}\n```\n\nThen ask your AI assistant to validate your oh-my-posh configuration.\n\n### Direct HTTP API\n\nYou can also use the validator directly via HTTP requests.\n\n#### Get Server Information\n\n```bash\ncurl https://ohmyposh.dev/api/mcp\n```\n\n#### List Available Tools\n\n```bash\ncurl -X POST https://ohmyposh.dev/api/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"tools/list\",\n    \"id\": 1\n  }'\n```\n\n#### Validate a Configuration\n\n```bash\ncurl -X POST https://ohmyposh.dev/api/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jsonrpc\": \"2.0\",\n    \"method\": \"tools/call\",\n    \"params\": {\n      \"name\": \"validate_config\",\n      \"arguments\": {\n        \"content\": \"{\\\"$schema\\\":\\\"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\\\",\\\"version\\\":4,\\\"blocks\\\":[]}\",\n        \"format\": \"json\"\n      }\n    },\n    \"id\": 1\n  }'\n```\n\n## Tool Parameters\n\n### validate_config\n\n**Parameters:**\n\n| Parameter | Type   | Required | Description                                                      |\n|-----------|--------|----------|------------------------------------------------------------------|\n| content   | string | Yes      | The configuration content as a string (JSON, YAML, or TOML)      |\n| format    | string | No       | The format: `json`, `yaml`, `toml`, or `auto` (default: `auto`) |\n\n**Returns:**\n\n```json\n{\n  \"valid\": true,\n  \"errors\": [],\n  \"warnings\": [\n    {\n      \"path\": \"$schema\",\n      \"message\": \"Consider adding \\\"$schema\\\" property for better editor support.\",\n      \"type\": \"recommendation\"\n    }\n  ],\n  \"detectedFormat\": \"json\",\n  \"parsedConfig\": { ... }\n}\n```\n\n## Response Fields\n\n| Field          | Type    | Description                                            |\n|----------------|---------|--------------------------------------------------------|\n| valid          | boolean | Whether the configuration is valid                     |\n| errors         | array   | List of validation errors (empty if valid)             |\n| warnings       | array   | List of warnings and recommendations                   |\n| detectedFormat | string  | The detected or specified format                       |\n| parsedConfig   | object  | The parsed configuration object                        |\n\n## Error Format\n\nEach error in the `errors` array contains:\n\n| Field   | Type   | Description                                  |\n|---------|--------|----------------------------------------------|\n| path    | string | JSON path to the problematic property        |\n| message | string | Human-readable error message                 |\n| keyword | string | The validation keyword that failed           |\n| params  | object | Additional parameters about the error        |\n| data    | any    | The actual data that failed validation       |\n\n## Examples\n\n### Valid Configuration\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 4,\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"type\": \"path\",\n          \"style\": \"powerline\",\n          \"background\": \"blue\",\n          \"foreground\": \"white\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n### Invalid Configuration Example\n\n```json\n{\n  \"blocks\": [\n    {\n      \"type\": \"invalid-type\"\n    }\n  ]\n}\n```\n\n**Validation Result:**\n\n```json\n{\n  \"valid\": false,\n  \"errors\": [\n    {\n      \"path\": \"/blocks/0/type\",\n      \"message\": \"Value must be one of: prompt, rprompt, line\",\n      \"keyword\": \"enum\"\n    }\n  ]\n}\n```\n\n## Integration Examples\n\n### Claude Desktop\n\nAdd to your Claude Desktop configuration (`~/Library/Application Support/Claude/config.json` on macOS):\n\n```json\n{\n  \"mcpServers\": {\n    \"oh-my-posh-validator\": {\n      \"url\": \"https://ohmyposh.dev/api/mcp\",\n      \"transport\": \"http\"\n    }\n  }\n}\n```\n\nThen ask Claude: \"Can you validate this oh-my-posh configuration for me?\" and paste your config.\n\n### Cline (VS Code Extension)\n\nConfigure Cline to use the MCP server, and it will automatically validate configurations when you're working on\noh-my-posh themes.\n\n## Supported Formats\n\n### JSON\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"version\": 4,\n  \"blocks\": []\n}\n```\n\n### YAML\n\n```yaml\n$schema: https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\nversion: 4\nblocks: []\n```\n\n### TOML\n\n```toml\nversion = 4\nblocks = []\n```\n\n## Privacy & Security\n\n- Your configuration content is **not stored** or logged\n- All validation is done in-memory and discarded after processing\n- The server only reads the official schema from the repository\n- No authentication required - fully anonymous\n\n## Source Code\n\nThe MCP server is open source and part of the oh-my-posh repository:\n\n- [MCP Server Function][mcp]\n- [Validator Module][validator]\n\n## Troubleshooting\n\n### Format Not Detected Correctly\n\nIf auto-detection fails, explicitly specify the format:\n\n```json\n{\n  \"arguments\": {\n    \"content\": \"...\",\n    \"format\": \"yaml\"\n  }\n}\n```\n\n### Parse Errors\n\nIf you get parse errors, check that your configuration is valid JSON/YAML/TOML syntax before validating the schema.\n\n### Schema Errors\n\nThe validator uses the latest schema from the main branch. If you're using an older oh-my-posh version, some newer\nproperties might not be recognized.\n\n## Contributing\n\nFound a bug or have a suggestion? Please [open an issue][issue] on GitHub.\n\n[mcp]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/website/api/mcp\n[validator]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/website/api/shared/validator.js\n[issue]: https://github.com/JanDeDobbeleer/oh-my-posh/issues\n"
  },
  {
    "path": "website/docs/auth.mdx",
    "content": "---\nid: auth\ntitle: Segment Authentication\nsidebar_label: Authentication\n---\n\nimport CodeBlock from '@site/src/components/Auth.js';\n\n<CodeBlock />\n"
  },
  {
    "path": "website/docs/configuration/block.mdx",
    "content": "---\nid: block\ntitle: Block\nsidebar_label: Block\n---\n\nLet's take a closer look at what defines a block.\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    blocks: [\n      {\n        type: \"prompt\",\n        alignment: \"left\",\n        segments: [],\n      },\n    ],\n  }}\n/>\n\n## Settings\n\n| Name               | Type      |\n| ------------------ | --------- |\n| `type`             | `string`  |\n| `newline`          | `boolean` |\n| `alignment`        | `string`  |\n| `filler`           | `string`  |\n| `overflow`         | `string`  |\n| `leading_diamond`  | `string`  |\n| `trailing_diamond` | `string`  |\n| `segments`         | `array`   |\n| `force`            | `boolean` |\n| `index`            | `int`     |\n\n### Type\n\nTells the engine what to do with the block. There are two options:\n\n- `prompt` renders one or more segments\n- `rprompt` renders one or more segments aligned to the right of the cursor. Only one `rprompt` block is permitted.\n  Supported on bash (with [ble.sh]), zsh, PowerShell, cmd, nu and fish.\n\n### Newline\n\nStart the block on a new line - defaults to `false`. For `pwsh` and `cmd` this will not print a newline\nthat's defined on the first block when the prompt is on the first line (when using clear), or when the shell session\nstarts (1st prompt). To enable the same behavior for `bash` and `zsh`, set `enable_cursor_positioning` to `true`.\nThis can have the side effect of swallowing commands you type while the prompt loads, or while the current\ncommand is still ongoing. This is a limitation of the shell and not Oh My Posh.\n\n### Alignment\n\n- `left`\n- `right`\n\nTell the engine if the block should be left or right-aligned.\n\n### Filler\n\nWhen you want to join a right and left aligned block with a repeated set of characters, add the character(s)\nto be repeated to this property. Add this property to the _right_ aligned block. This supports the use of\n[color overrides][color-overrides].\n\n<Config\n  data={{\n    blocks: [\n      {\n        alignment: \"right\",\n        filler: \".\",\n      },\n    ],\n  }}\n/>\n\nFiller allows you to specify a template to tweak the text used as filler. This template behaves the same as\nSegment templates, however, fewer properties are available.\n\n| Name        | Type   | Description                                                           |\n| ----------- | ------ | --------------------------------------------------------------------- |\n| `.Overflow` | `text` | if no overflow was needed, this is empty. Otherwise `hide` or `break` |\n| `.Padding`  | `int`  | the computed length of the padding between left and right blocks      |\n\nThis can be very useful if you wish to use a filler text when there is no overflow and use\nempty space when the right block is hidden or drawn on a newline due to overflow.\n\n<Config\n  data={{\n    blocks: [\n      {\n        alignment: \"right\",\n        overflow: \"hide\",\n        filler: \"{{ if .Overflow }} {{ else }}-{{ end }}\",\n      },\n    ],\n  }}\n/>\n\n### Overflow\n\n- `break`\n- `hide`\n\nWhen the right aligned block is so long it will overflow the left aligned block, the engine will either\nbreak the block or hide it based on the setting. By default it is printed as is on the same line.\n\n### Leading Diamond\n\nThe character to use as a leading diamond for the first segment in case you always want to start the block\nwith the same leading diamond, regardless of which segment is enabled or not.\n\n### Trailing Diamond\n\nThe character to use as a trailing diamond for the last segment in case you always want to end the block\nwith the same trailing diamond, regardless of which segment is enabled or not.\n\n### Segments\n\nArray of one or more [segments][segment].\n\n### Force\n\nWhen set to `true`, the block will always be rendered, even if all segments are empty. Defaults to `false`.\n\n### Index\n\nThe index of the block in the configuration. This is used to [override] a specific block in a base configuration.\nThis is a 1-based index, so the first block has an index of `1`.\n\n[ble.sh]: https://github.com/akinomyoga/ble.sh\n[color-overrides]: /docs/configuration/colors#color-overrides\n[segment]: segment.mdx\n[override]: /docs/configuration/general#extends\n"
  },
  {
    "path": "website/docs/configuration/colors.mdx",
    "content": "---\nid: colors\ntitle: Colors\nsidebar_label: Colors\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n## Standard colors\n\nOh My Posh supports multiple different color references, being:\n\n- True color using [hex colors][hexcolors] (for example `#CB4B16`).\n- 16 [ANSI color names][ansicolors].\n  These include 8 basic ANSI colors and `default`\n\n  `black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`\n\n  as well as 8 extended ANSI colors:\n\n  `darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`\n\n- 256 color palette using their number representation.\n  For example `0` is black, `1` is red, `2` is green, etc.\n- The `transparent` keyword which can be used to create either a transparent foreground override\n  or transparent background color using the segment's foreground property.\n- The `foreground` keyword which can be used to reference the current segment's foreground color.\n- The `background` keyword which can be used to reference the current segment's background color.\n- The `parentForeground` keyword which can be used to inherit the previous active segment's foreground color.\n- The `parentBackground` keyword which can be used to inherit the previous active segment's background color.\n- The `accent` keyword which references the OS accent color (Windows and macOS only).\n\n## Color templates\n\nArray of string [templates][templates] to define the color based on the current context.\nUnder the hood this uses go's [text/template][go-text-template] feature extended with [sprig][sprig] and\noffers a few standard properties to work with. For segments, you can look at the **Template Properties**\nsection in the documentation. The general template properties are listed [here][template-properties].\n\nThe following sample is based on the [AWS Segment][aws].\n\n<Config\n  data={{\n    type: \"aws\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#111111\",\n    foreground_templates: [\n      '{{if contains \"default\" .Profile}}#FFA400{{end}}',\n      '{{if contains \"jan\" .Profile}}#f1184c{{end}}',\n    ],\n  }}\n/>\n\nThe logic is as follows: when `foreground_templates` contains an array, we will check every template line until there's\none that returns a non-empty string. So, when the contents of `.Profile` contain the word `default`, the first template\nreturns `#FFA400` and that's the color that will be used. If it contains `jan`, it returns `#f1184c`. When none of the\ntemplates returns a value, the foreground value `#ffffff` is used as a fallback value.\n\n## Color overrides\n\nYou have the ability to override the foreground and/or background color for text in any property that accepts it.\nThe syntax is custom but should be rather straight-forward: `<foreground,background>text</>`. For example,\n`<#ffffff,#000000>this is white with black background</> <#FF479C>but this is pink</>`.\nAnything between the color start `<#FF479C>` and end `</>` will be colored accordingly.\n\nIf you want to print a colored bracket that isn't the same as the segment's `foreground`, you can\ndo so like this:\n\n<Config\n  data={{\n    template: \"<#CB4B16>┏[</>\",\n  }}\n/>\n\nIf you also wanted to change the background color in the previous command, you would do so like this:\n\n<Config\n  data={{\n    template: \"<#CB4B16,#FFFFFF>┏[</>\",\n  }}\n/>\n\nTo change _only_ the background color, just omit the first color from the above string:\n\n<Config\n  data={{\n    template: \"<,#FFFFFF>┏[</>\",\n  }}\n/>\n\n## Palette\n\nIf your configuration defined the Palette, you can use the _Palette reference_ `p:<palette key>` in places where the\n**Standard color** is expected.\n\n### Defining a Palette\n\nPalette is a set of named **Standard colors**. To use a Palette, define a `\"palette\"` object\nat the top level of your configuration:\n\n<Config\n  data={{\n    palette: {\n      \"git-foreground\": \"#193549\",\n      git: \"#FFFB38\",\n      \"git-modified\": \"#FF9248\",\n      \"git-diverged\": \"#FF4500\",\n      \"git-ahead\": \"#B388FF\",\n      \"git-behind\": \"#B388FF\",\n      red: \"#FF0000\",\n      green: \"#00FF00\",\n      blue: \"#0000FF\",\n      white: \"#FFFFFF\",\n      black: \"#111111\",\n    },\n  }}\n/>\n\nColor names (palette keys) can have any string value, so be creative.\nColor values, on the other hand, should adhere to the **Standard color** format.\n\n### Using a Palette\n\nYou can now use _Palette references_ in any [Segment's][segment] `foreground`, `foreground_templates`,\n`background`, `background_templates` properties, and other config properties that expect **Standard color** value.\n_Palette reference_ format is `p:<palette key>`. Take a look at the [Git][git] segment using _Palette references_:\n\n<Config\n  data={{\n    type: \"git\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"p:git-foreground\",\n    background: \"p:git\",\n    background_templates: [\n      \"{{ if or (.Working.Changed) (.Staging.Changed) }}p:git-modified{{ end }}\",\n      \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}p:git-diverged{{ end }}\",\n      \"{{ if gt .Ahead 0 }}p:git-ahead{{ end }}\",\n      \"{{ if gt .Behind 0 }}p:git-behind{{ end }}\",\n    ],\n  }}\n/>\n\nHaving all of the colors defined in one place allows you to import existing color configurations (usually with slight\ntweaking to adhere to the format), easily change colors of multiple segments at once, and have a more\norganized configuration overall. Be creative!\n\n### _Palette references_ and **Standard colors**\n\nUsing Palette does not interfere with using **Standard colors** in your configuration. You can still use **Standard colors**\neverywhere. This can be useful if you want to use a specific color for a single segment element, or in a\n_Color override_ ([Battery segment][battery]):\n\n<Config\n  data={{\n    type: \"battery\",\n    style: \"powerline\",\n    invert_powerline: true,\n    powerline_symbol: \"\\uE0B2\",\n    foreground: \"p:white\",\n    background: \"p:black\",\n    options: {\n      discharging_icon: \"<#ffa500>-</> \",\n      charging_icon: \"+ \",\n      charged_icon: \"* \",\n    },\n  }}\n/>\n\n### Handling of invalid references\n\nShould you use an invalid _Palette reference_ as a color (for example typo `p:bleu` instead of `p:blue`),\nthe Palette engine will use the Transparent keyword as a fallback value. So if you see your prompt segments\nrendered with incorrect colors, and you are using a Palette, be sure to check the correctness of your references.\n\n### Recursive resolution\n\nPalette allows for recursive _Palette reference_ resolution. You can use a _Palette reference_ as a color\nvalue in Palette. This allows you to define named colors, and use references to those colors as Palette values.\nFor example, `p:foreground` and `p:background` will be correctly set to \"#CAF0F80\" and \"#023E8A\":\n\n<Config\n  data={{\n    palette: {\n      \"light-blue\": \"#CAF0F8\",\n      \"dark-blue\": \"#023E8A\",\n      foreground: \"p:light-blue\",\n      background: \"p:dark-blue\",\n    },\n  }}\n/>\n\n## Palettes\n\nIf you want to use a `palette` conditionally, for example for **light or dark mode**, you can define multiple\n`palettes` and a [template][templates] that resolves to the `palette` key. The `template` is evaluated at\nruntime so your prompt can change at any time based on the outcome of the `template`.\n\nTake the following configuration:\n\n<Config\n  data={{\n    palettes: {\n      template: '{{ if eq .Shell \"pwsh\" }}latte{{ else }}frappe{{ end }}',\n      list: {\n        latte: {\n          black: \"#262B44\",\n          green: \"#59C9A5\",\n          orange: \"#F07623\",\n          red: \"#e64553\",\n          white: \"#E0DEF4\",\n          yellow: \"#df8e1d\",\n          blue: \"#7287fd\",\n        },\n        frappe: {\n          black: \"#262B44\",\n          green: \"#59C9A5\",\n          orange: \"#F07623\",\n          red: \"#D81E5B\",\n          white: \"#E0DEF4\",\n          yellow: \"#F3AE35\",\n          blue: \"#4B95E9\",\n        },\n      },\n    },\n  }}\n/>\n\nIn this case, when the shell is `pwsh`, the `latte` palette will be used, otherwise it uses the `frappe` palette. If you want,\nyou could also add `frappe` as the default `palette`, given that one is used as a fallback when not match can be found based on what\nthe `template` resolves to. In case no match is available and no `palette` is defined, it will also fallback to `transparent`\nfor any palette color reference in templates/colors.\n\nIf you want to avoid color duplication, you can use palettes in combination with the `palette` property. This way you can define\na color once and reuse it in multiple palettes. For example:\n\n<Config\n  data={{\n    palette: {\n      black: \"#262B44\",\n      green: \"#59C9A5\",\n      orange: \"#F07623\",\n    },\n    palettes: {\n      template: '{{ if eq .Shell \"pwsh\" }}latte{{ else }}frappe{{ end }}',\n      list: {\n        latte: {\n          red: \"#e64553\",\n          white: \"#E0DEF4\",\n          yellow: \"#df8e1d\",\n          blue: \"#7287fd\",\n        },\n        frappe: {\n          red: \"#D81E5B\",\n          white: \"#E0DEF4\",\n          yellow: \"#F3AE35\",\n          blue: \"#4B95E9\",\n        },\n      },\n    },\n  }}\n/>\n\n:::info\nIf a color is defined in both palette and palettes, the palettes' resolved color will take precedence.\n:::\n\n## Cycle\n\nWhen you want to display the same **sequence of colors** (background and foreground) regardless of which segments are active, you can\nmake use of the cycle property. This property is a list of colors which are used one after the other in a continuous loop. A defined\ncycle always gets precedence over everything else.\n\n<Config\n  data={{\n    cycle: [\n      {\n        background: \"p:blue\",\n        foreground: \"p:white\",\n      },\n      {\n        background: \"p:green\",\n        foreground: \"p:black\",\n      },\n      {\n        background: \"p:orange\",\n        foreground: \"p:white\",\n      },\n    ],\n  }}\n/>\n\n[hexcolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/\n[ansicolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/\n[git]: /docs/segments/scm/git\n[battery]: /docs/segments/system/battery\n[template-properties]: /docs/configuration/templates#global-properties\n[aws]: /docs/segments/cloud/aws\n[go-text-template]: https://golang.org/pkg/text/template/\n[segment]: /docs/configuration/segment\n[sprig]: https://masterminds.github.io/sprig/\n[templates]: templates.mdx\n"
  },
  {
    "path": "website/docs/configuration/debug-prompt.mdx",
    "content": "---\nid: debug-prompt\ntitle: Debug prompt\nsidebar_label: Debug prompt\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n:::info\nThis feature only works in `powershell` for the time being.\n:::\n\nThe debug prompt is displayed when you debug a script from the command line or Visual Studio Code.\nThe default is `[DBG]: `.\n\nYou can use go [text/template][go-text-template] [templates][templates] extended with [sprig][sprig] to enrich the text.\nEnvironment variables are available, just like the [`console_title_template`][console-title] functionality.\n\n## Configuration\n\nYou need to extend or create a custom theme with your debug prompt override. For example:\n\n<Config\n  data={{\n    debug_prompt: {\n      background: \"transparent\",\n      foreground: \"#ffffff\",\n      template: \"Debugging \",\n    },\n  }}\n/>\n\n## Options\n\n| Name                   | Type     | Description                                                                                                                         |\n| ---------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |\n| `foreground`           | `string` | [color][colors]                                                                                                                     |\n| `foreground_templates` | `string` | [color templates][color-templates]                                                                                                  |\n| `background`           | `string` | [color][colors]                                                                                                                     |\n| `background_templates` | `string` | [color templates][color-templates]                                                                                                  |\n| `template`             | `string` | a go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the properties below - defaults to `[DBG]: ` |\n\n## Template ([info][templates])\n\n| Name           | Type      | Description                                                               |\n| -------------- | --------- | ------------------------------------------------------------------------- |\n| `.Root`        | `boolean` | is the current user root/admin or not                                     |\n| `.PWD`         | `string`  | the current working directory                                             |\n| `.Folder`      | `string`  | the current working folder                                                |\n| `.Shell`       | `string`  | the current shell name                                                    |\n| `.UserName`    | `string`  | the current user name                                                     |\n| `.HostName`    | `string`  | the host name                                                             |\n| `.Code`        | `int`     | the last exit code                                                        |\n| `.Env.VarName` | `string`  | Any environment variable where `VarName` is the environment variable name |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[sprig]: https://masterminds.github.io/sprig/\n[console-title]: /docs/configuration/title#console-title-template\n[templates]: /docs/configuration/templates\n[colors]: /docs/configuration/colors\n[color-templates]: /docs/configuration/colors#color-templates\n"
  },
  {
    "path": "website/docs/configuration/general.mdx",
    "content": "---\nid: general\ntitle: General\nsidebar_label: General\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\nOh My Posh renders your prompt based on the definition of _blocks_ (like Lego) which contain one or more _segments_.\nA really simple configuration could look like this. The default format is `json`, but we also support `toml` and `yaml`.\nThere's a [schema][schema] available which is kept up-to-date and helps with autocomplete and validation of the configuration.\n\n:::info\nThere are a few [themes][themes] available which are basically predefined configurations. You can use these as they are, or as a\nstarting point to create your own configuration.\n:::\n\n<Tabs\n  defaultValue=\"json\"\n  groupId=\"sample\"\n  values={[\n    { label: 'json', value: 'json', },\n    { label: 'yaml', value: 'yaml', },\n    { label: 'toml', value: 'toml', },\n  ]\n}>\n<TabItem value=\"json\">\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n  \"final_space\": true,\n  \"version\": 4,\n  \"blocks\": [\n    {\n      \"type\": \"prompt\",\n      \"alignment\": \"left\",\n      \"segments\": [\n        {\n          \"type\": \"path\",\n          \"style\": \"powerline\",\n          \"powerline_symbol\": \"\\uE0B0\",\n          \"foreground\": \"#ffffff\",\n          \"background\": \"#61AFEF\",\n          \"options\": {\n            \"style\": \"folder\"\n          }\n        }\n      ]\n    }\n  ]\n}\n```\n\n</TabItem>\n<TabItem value=\"yaml\">\n\n```yaml\n# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\nfinal_space: true\nversion: 4\nblocks:\n  - type: prompt\n    alignment: left\n    segments:\n      - type: path\n        style: powerline\n        powerline_symbol: \"\"\n        foreground: \"#ffffff\"\n        background: \"#61AFEF\"\n        options:\n          style: folder\n```\n\n</TabItem>\n<TabItem value=\"toml\">\n\n```toml\n\"$schema\" = \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\"\nfinal_space = true\nversion = 4\n\n[[blocks]]\ntype = \"prompt\"\nalignment = \"left\"\n\n  [[blocks.segments]]\n  type = \"path\"\n  style = \"powerline\"\n  powerline_symbol = \"\"\n  foreground = \"#ffffff\"\n  background = \"#61AFEF\"\n\n    [blocks.segments.options]\n    style = \"folder\"\n```\n\n</TabItem>\n</Tabs>\n\nWith this configuration, a single powerline segment is rendered that shows the name of the folder you're currently in.\nTo set this configuration in combination with an Oh My Posh [executable][releases], use the `--config` flag to\nset a path to a file containing the above code. The `--shell universal` flag is used to print the prompt without\nescape characters to see the prompt as it would be shown inside a prompt function for your shell.\n\n:::caution\nThe command below will not persist the configuration for your shell but print the prompt in your terminal.\nIf you want to use your own configuration permanently, adjust the prompt configuration to use your custom\nconfiguration.\n:::\n\n```bash\noh-my-posh print primary --config sample.json --shell uni\n```\n\nIf all goes according to plan, you should see the prompt being printed out on the line below. In case you see a lot of\nboxes with question marks, set up your terminal to use a [supported font][font] before continuing.\n\n:::tip\nThe `--config` flag can accept either a local filepath or a remotely hosted config file.\n\nFor example, the following is a valid `--config` flag:\n`--config 'https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/jandedobbeleer.omp.json'`\n:::\n\n## Settings\n\n| Name                        | Type             | Default | Description                                                                                                                                                                                                                                                                  |\n| --------------------------- | ---------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `final_space`               | `boolean`        |         | when true adds a space at the end of the prompt                                                                                                                                                                                                                              |\n| `pwd`                       | `string`         |         | notify terminal of current working directory, values can be `osc99`, `osc7` or `osc51` depending on your terminal. Supports [templates][templates]                                                                                                                           |\n| `terminal_background`       | `string`         |         | [color][colors] - terminal background color, set to your terminal's background color when you notice black elements in Windows Terminal or the Visual Studio Code integrated terminal                                                                                        |\n| `accent_color`              | `string`         |         | [color][colors] - accent color, used as a fallback when the `accent` [color][accent] is not supported                                                                                                                                                                        |\n| `var`                       | `map[string]any` |         | config variables to use in [templates][templates]. Can be any value                                                                                                                                                                                                          |\n| `shell_integration`         | `boolean`        | `false` | enable shell integration using FinalTerm's OSC sequences. Works in bash, cmd (Clink v1.14.25+), fish, powershell and zsh                                                                                                                                                     |\n| `enable_cursor_positioning` | `boolean`        | `false` | enable fetching the cursor position in bash and zsh to allow automatic hiding of leading newlines when at the top of the shell                                                                                                                                               |\n| `patch_pwsh_bleed`          | `boolean`        | `false` | patch a PowerShell bug where the background colors bleed into the next line at the end of the buffer (can be removed when [this][pwsh-bleed] is merged)                                                                                                                      |\n| `upgrade`                   | `Upgrade`        |         | enable auto upgrade or the upgrade notice. See [Upgrade]                                                                                                                                                                                                                     |\n| `iterm_features`            | `[]string`       | `false` | enable iTerm2 specific features:<ul><li>`prompt_mark`: add the `iterm2_prompt_mark` [function][iterm2-si] for supported shells</li><li>`current_dir`: expose the current directory for iTerm2</li><li>`remote_host`: expose the current remote and user for iTerm2</li></ul> |\n| `maps`                      | [`Maps`](#maps)  |         | a list of custom text mappings                                                                                                                                                                                                                                               |\n| `async`                     | `boolean`        | `false` | load the prompt async. Will either load the standard prompt, or allow you to start typing right away. Supported for `pwsh`, `powershell`, `zsh`, `bash` and `fish`                                                                                                           |\n| `version`                   | `int`            | `4`     | the config version, currently at `4`                                                                                                                                                                                                                                         |\n| `extends`                   | `string`         |         | the configuration to [extend] from                                                                                                                                                                                                                                           |\n| `streaming`                 | `int`            |         | enable streaming mode with a timeout in milliseconds for pending segments. See [streaming]                                                                                                                                                                                   |\n\n### Maps\n\n| Name         | Type     | Description                                                                           |\n| ------------ | -------- | ------------------------------------------------------------------------------------- |\n| `user_name`  | `object` | text replacement mapping for user names                                               |\n| `host_name`  | `object` | text replacement mapping for host names                                               |\n| `shell_name` | `object` | text replacement mapping for shell names. This modifies the `.Shell` global property. |\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    maps: {\n      user_name: {\n        jan: \"🚀\",\n        root: \"⚡\"\n      },\n      host_name: {\n        laptop123: \"work\"\n      }\n    }\n  }}\n/>\n\n### Extends\n\nThe `extends` key allows you to extend an existing configuration. This is useful when you want to build upon a base configuration without\nduplicating all the settings like a [theme][themes]. The value should be a path to another configuration file, which can be either local or remote.\n\nReplacing values is done by repeating the value in the new configuration. For example, if you want to change the `accent_color` in a base configuration,\nyou can do so by specifying the `accent_color` key in your new configuration. The new value will override the one in the base configuration.\n\nTo override segments and blocks, specify the block using the same `type` and `alignment` as the base configuration. You can then add or modify the segments\nwithin that block. Segments are matched by their `alias` or `type`, so you can add new segments or modify existing ones without affecting the rest of the configuration.\n\nFor more advanced use cases, you can also specify the index of the `block` or `segment` you want to override. This allows you to override `blocks` or `segments` at\nspecific positions in the configuration. Be aware that the index is **1-based**, so the first `block` or `segment` has an index of `1`.\n\n### JSON Schema Validation\n\nAs mentioned above, Oh My Posh configurations can utilize JSON Schema to validate their contents. Configurations should include a link to\nthe [external schema document][schema] which prescribes the appropriate structure and contents for various elements. If\nyour code editor is configured to use JSON Schema, it will compare your configuration to the external document, and issue\nwarnings for discrepancies.\n\nFor example, given the following code:\n\n```json\n...\n\"segments\": [\n  {\n    \"type\": \"an_invalid_entry\",\n    \"template\": \"{{ if gt .Code 0 }}\\uf134{{ end }}\",\n  }\n]\n...\n```\n\nWarnings will be raised for type, since `an_invalid_entry` is not in the list of acceptable values, as well as\nfor the entire segment item (enclosed in `{}`), since it lacks the required `style` key. Take advantage of these\nwarnings, and ignore them at your peril.\n\n### Accepted Formats\n\nOh My Posh supports three file formats for configurations: `json`, `yaml`, and `toml`.\n\nVarious converters exist to convert between these, although they aren't perfect and will require manual\nadjustment. Notably, the schema implementation for json is as follows:\n\n```json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\"\n}\n```\n\nWhile for yaml:\n\n```yaml\n# yaml-language-server: $schema=https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\n```\n\nConverters won't catch this change, so you will need to adjust manually.\n\n[releases]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest\n[font]: /docs/installation/fonts\n[schema]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/schema.json\n[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes\n[colors]: /docs/configuration/colors\n[accent]: /docs/configuration/colors#standard-colors\n[templates]: /docs/configuration/templates#config-variables\n[pwsh-bleed]: https://github.com/PowerShell/PowerShell/pull/19019\n[iterm2-si]: https://iterm2.com/documentation-shell-integration.html\n[Upgrade]: /docs/installation/upgrade\n[extend]: /docs/configuration/general#extends\n[streaming]: /docs/experimental/streaming\n"
  },
  {
    "path": "website/docs/configuration/introduction.mdx",
    "content": "---\nid: introduction\ntitle: Introduction\nsidebar_label: 👋 Introduction\nslug: /\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\nOh My Posh is a custom prompt engine for any shell that has the ability to adjust\nthe prompt string with a function or variable.\n\n## Concept\n\nTraditionally, prompt tools work with custom scripts per theme (just like [Oh My Posh 2][omp] did) or a lot\nof CLI configuration switches to define what it looks like. With Oh My Posh, I wanted to start from a single\nconfiguration file that could easily be shared anywhere, removing the need to really grasp what goes on underneath.\n\nWhen you look at prompts like Agnoster or Paradox, you notice they usually consist of a few building\n**blocks** which contain one or more **segments** that display some sort of information. The configuration of\nOh My Posh works exactly like that. Blocks are a combination of one or more segments.\n\nThe basic layout of the config file is as follows.\n\n<Config\n  data={{\n    \"blocks\": []\n  }}\n/>\n\nA [block][block] has properties that indicate its position and the [segments][segment] it will render.\n\n<Config\n  data={{\n    \"blocks\": [\n      {\n        \"segments\": []\n      }\n    ]\n  }}\n/>\n\nA [segment][segment] renders a single context like showing the current folder, user information or git status\nwhen relevant. It can be styled any way you want, resulting in visualizing the prompt you are looking for.\n\nFor your convenience, the existing [themes][themes] from [Oh My Posh][themes] have been added to version 4, so you\ncan get started even without having to understand the theming. So, let's no longer waste time on theory, have a look at\nthe installation guide to get started right away!\n\n[omp]: https://github.com/JanDeDobbeleer/oh-my-posh2\n[block]: /docs/configuration/block\n[segment]: /docs/configuration/segment\n[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes\n"
  },
  {
    "path": "website/docs/configuration/line-error.mdx",
    "content": "---\nid: line-error\ntitle: Line error\nsidebar_label: Line error\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n:::info\nThis feature only works in `powershell` for the time being.\n:::\n\nLine error, when enabled, replaces the last part of the prompt when the text entered is invalid. It leverages\n[PSReadLine's][psreadline] `-PromptText` setting by adding two distinct prompts. One for a valid line,\nand one for when there's an error. As PSReadLine will rewrite the last part of\nyour prompt with the value of either based on the line's context, you will need to make sure everything\nis compatible with your config as **these values are only set once** on shell start.\n\nThere are two config settings you need to tweak:\n\n- `valid_line`: displays when the line is valid (again)\n- `error_line`: displays when the line is faulty\n\nYou can use go [text/template][go-text-template] templates extended with [sprig][sprig] to enrich the text.\n\n## Configuration\n\nYou need to extend or create a custom theme with your prompt overrides. For example:\n\n<Config\n  data={{\n    valid_line: {\n      background: \"transparent\",\n      foreground: \"#ffffff\",\n      template: \"<#e0def4,#286983>\\uf42e </><#286983,transparent>\\ue0b4</> \",\n    },\n    error_line: {\n      background: \"transparent\",\n      foreground: \"#ffffff\",\n      template: \"<#eb6f92,#286983>\\ue009 </><#286983,transparent>\\ue0b4</> \",\n    },\n  }}\n/>\n\n## Options\n\n| Name         | Type     | Description                                                |\n| ------------ | -------- | ---------------------------------------------------------- |\n| `background` | `string` | [color][colors]                                            |\n| `foreground` | `string` | [color][colors]                                            |\n| `template`   | `string` | a fully featured [template][templates] - defaults to empty |\n\n[colors]: /docs/configuration/colors\n[go-text-template]: https://golang.org/pkg/text/template/\n[sprig]: https://masterminds.github.io/sprig/\n[psreadline]: https://github.com/PowerShell/PSReadLine\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/configuration/sample.mdx",
    "content": "---\nid: sample\ntitle: Sample\nsidebar_label: Sample\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    $schema:\n      \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\",\n    blocks: [\n      {\n        segments: [\n          {\n            foreground: \"#007ACC\",\n            template: \" {{ .CurrentDate | date .Format }} \",\n            options: {\n              time_format: \"15:04:05\",\n            },\n            style: \"plain\",\n            type: \"time\",\n          },\n        ],\n        type: \"rprompt\",\n      },\n      {\n        alignment: \"left\",\n        newline: true,\n        segments: [\n          {\n            background: \"#ffb300\",\n            foreground: \"#ffffff\",\n            leading_diamond: \"\\ue0b6\",\n            template: \" {{ .UserName }} \",\n            style: \"diamond\",\n            trailing_diamond: \"\\ue0b0\",\n            type: \"session\",\n          },\n          {\n            background: \"#61AFEF\",\n            foreground: \"#ffffff\",\n            powerline_symbol: \"\\ue0b0\",\n            template: \" {{ .Path }} \",\n            options: {\n              style: \"folder\",\n            },\n            exclude_folders: [\"/super/secret/project\"],\n            style: \"powerline\",\n            type: \"path\",\n          },\n          {\n            background: \"#2e9599\",\n            background_templates: [\n              \"{{ if or (.Working.Changed) (.Staging.Changed) }}#f36943{{ end }}\",\n              \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#a8216b{{ end }}\",\n              \"{{ if gt .Ahead 0 }}#35b5ff{{ end }}\",\n              \"{{ if gt .Behind 0 }}#f89cfa{{ end }}\",\n            ],\n            foreground: \"#193549\",\n            foreground_templates: [\n              \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#ffffff{{ end }}\",\n            ],\n            powerline_symbol: \"\\ue0b0\",\n            template:\n              \" {{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }} \",\n            options: {\n              branch_template: \"{{ trunc 25 .Branch }}\",\n              fetch_status: true,\n            },\n            style: \"powerline\",\n            type: \"git\",\n          },\n          {\n            background: \"#00897b\",\n            background_templates: [\"{{ if gt .Code 0 }}#e91e63{{ end }}\"],\n            foreground: \"#ffffff\",\n            template: \"<parentBackground>\\ue0b0</> \\ue23a \",\n            options: {\n              always_enabled: true,\n            },\n            style: \"diamond\",\n            trailing_diamond: \"\\ue0b4\",\n            type: \"status\",\n          },\n        ],\n        type: \"prompt\",\n      },\n    ],\n    final_space: true,\n    version: 4,\n  }}\n/>\n"
  },
  {
    "path": "website/docs/configuration/secondary-prompt.mdx",
    "content": "---\nid: secondary-prompt\ntitle: Secondary prompt\nsidebar_label: Secondary prompt\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n:::info\nThis feature only works in `powershell`, `zsh` and `bash` for the time being.\n:::\n\nThe secondary prompt is displayed when a command text spans multiple lines. The default is `> `.\n\nYou can use go [text/template][go-text-template] templates extended with [sprig][sprig] to enrich the text.\nEnvironment variables are available, just like the [`console_title_template`][console-title] functionality.\n\n## Configuration\n\nYou need to extend or create a custom theme with your secondary prompt override. For example:\n\n<Config\n  data={{\n    secondary_prompt: {\n      background: \"transparent\",\n      foreground: \"#ffffff\",\n      template: \"-> \",\n    },\n  }}\n/>\n\n## Options\n\n| Name         | Type     | Description                                                                                                                    |\n| ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `background` | `string` | [color][colors]                                                                                                                |\n| `foreground` | `string` | [color][colors]                                                                                                                |\n| `template`   | `string` | a go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the properties below - defaults to `> ` |\n\n## Template ([info][templates])\n\n| Name        | Type      | Description                           |\n| ----------- | --------- | ------------------------------------- |\n| `.Root`     | `boolean` | is the current user root/admin or not |\n| `.Shell`    | `string`  | the current shell name                |\n| `.UserName` | `string`  | the current user name                 |\n| `.HostName` | `string`  | the host name                         |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[sprig]: https://masterminds.github.io/sprig/\n[console-title]: /docs/configuration/title#console-title-template\n[templates]: /docs/configuration/templates\n[colors]: /docs/configuration/colors\n"
  },
  {
    "path": "website/docs/configuration/segment.mdx",
    "content": "---\nid: segment\ntitle: Segment\nsidebar_label: Segment\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\nA segment is a part of the prompt with a certain context. There are different types available out-of-the-box, if you're\nlooking for what's included, feel free to skip this part and browse through the [segments][segments]. Keep reading to\nunderstand how to configure a segment.\n\n<Config\n  data={{\n    blocks: [\n      {\n        segments: [\n          {\n            type: \"path\",\n            style: \"powerline\",\n            powerline_symbol: \"\\uE0B0\",\n            foreground: \"#ffffff\",\n            background: \"#61AFEF\",\n            template: \" {{ .Path }} \",\n            include_folders: [\"/Users/posh/Projects\"],\n          },\n        ],\n      },\n    ],\n  }}\n/>\n\n## Settings\n\n| Name                       | Type         | Default | Description                                                                                                                                                                                                                                                                                                                                                                               |\n| -------------------------- | ------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `type`                     | `string`     |         | takes the `string` value referencing which segment logic it needs to run (see [segments][segments] for possible values)                                                                                                                                                                                                                                                                   |\n| `style`                    | `string`     | `plain` | see [Style][style] below. Possible values:<ul><li>`powerline`</li><li>`plain`</li><li>`diamond`</li><li>`accordion`</li><li>a go [text/template][go-text-template] [template][templates] resolving to the above values</li></ul>                                                                                                                                                          |\n| `powerline_symbol`         | `string`     |         | character to use at the end of the segment when `\"style\": \"powerline\"` (e.g., `\\uE0B0`)                                                                                                                                                                                                                                                                                                   |\n| `leading_powerline_symbol` | `string`     |         | character to use at the start of the segment when `\"style\": \"powerline\"`. By default, Oh My Posh uses an ANSI hack to invert the `powerline_symbol`, which provides the best alignment but may not work in all terminals. If you see black artifacts at segment starts, set this to the corresponding opening glyph (e.g., `\\uE0D6` when using `\\uE0B0`, or `\\uE0D7` when using `\\uE0B1`) |\n| `invert_powerline`         | `boolean`    | `false` | if `true` swaps the foreground and background colors. Can be useful when the character you want does not exist in the perfectly mirrored variant for example - defaults to `false`                                                                                                                                                                                                        |\n| `leading_diamond`          | `string`     |         | character to use at the start of the segment. Will take the background color of the segment as its foreground color                                                                                                                                                                                                                                                                       |\n| `trailing_diamond`         | `string`     |         | character to use at the end of the segment. Will take the background color of the segment as its foreground color                                                                                                                                                                                                                                                                         |\n| `foreground`               | `string`     |         | [color][colors]                                                                                                                                                                                                                                                                                                                                                                           |\n| `foreground_templates`     | `[]Template` |         | [color templates][color-templates]                                                                                                                                                                                                                                                                                                                                                        |\n| `background`               | `string`     |         | [color][colors]                                                                                                                                                                                                                                                                                                                                                                           |\n| `background_templates`     | `[]Template` |         | [color templates][color-templates]                                                                                                                                                                                                                                                                                                                                                        |\n| `template`                 | `string`     |         | a go [text/template][go-text-template] [template][templates] to render the prompt                                                                                                                                                                                                                                                                                                         |\n| `templates`                | `[]Template` |         | in some cases having a single [template][templates] string is a bit cumbersome. Templates allows you to span the segment's [template][templates] string multiple lines where every [template][templates] is evaluated and depending on what you aim to achieve, there are two possible outcomes based on `templates_logic`                                                                |\n| `templates_logic`          | `string`     | `join`  | <ul><li>`first_match`: return the first non-whitespace string and skip everything else</li><li>`join`:evaluate all templates and join all non-whitespace strings (**default**)</li></ul>                                                                                                                                                                                                  |\n| `options`                  | `[]Option`   |         | see [Options][options] below                                                                                                                                                                                                                                                                                                                                                              |\n| `interactive`              | `boolean`    | `false` | when true, the segment text is not escaped to allow the use of interactive prompt escape sequences in Bash/Zsh - defaults to `false`                                                                                                                                                                                                                                                      |\n| `alias`                    | `string`     |         | for use with [cross segment template properties][cstp]                                                                                                                                                                                                                                                                                                                                    |\n| `min_width`                | `int`        |   `0`   | if the terminal width is smaller than this value, the segment will be hidden. For your terminal width, see `oh-my-posh get width`. Defaults to `0` (disable)                                                                                                                                                                                                                              |\n| `max_width`                | `int`        |   `0`   | if the terminal width exceeds this value, the segment will be hidden. For your terminal width, see `oh-my-posh get width`. Defaults to `0` (disable)                                                                                                                                                                                                                                      |\n| `cache`                    | `Cache`      |         | how to cache the segment to avoid fetching information too much, see [below][cache]                                                                                                                                                                                                                                                                                                       |\n| `include_folders`          | `[]string`   |         | define which folders to include to enable the segment, see [below][include-exclude]                                                                                                                                                                                                                                                                                                       |\n| `exclude_folders`          | `[]string`   |         | define which folders to exclude to disable the segment, see [below][include-exclude]                                                                                                                                                                                                                                                                                                      |\n| `force`                    | `boolean`    | `false` | when true, the segment is always rendered, even when it's only whitespace - defaults to `false`                                                                                                                                                                                                                                                                                           |\n| `timeout`                  | `int`        |   `0`   | timeout in milliseconds for segment execution. If the segment takes longer than this value to complete, it will be disabled. Defaults to `0` (no timeout)                                                                                                                                                                                                                                 |\n| `index`                    | `int`        |         | used to [override] a specific segment (1-based)                                                                                                                                                                                                                                                                                                                                           |\n| `placeholder`              | `string`     |         | text to display while the segment is loading in [streaming mode][streaming]. Defaults to `...`                                                                                                                                                                                                                                                                                                         |\n\n:::warning\nIn Bash/Zsh, when the property `interactive` is `true` for a segment, the prompt length calculation can be wrong\nbecause of possible string expansions (e.g., `\\w` in Bash and `%d` in Zsh which both expand to the current working\ndirectory), thus a right-aligned block is not being properly right-aligned.\n\nUnfortunately, it's not possible for Oh My Posh to know the final prompt length since the string expansion is done\nby your shell, so use this at your own risk.\n:::\n\n## Style\n\nStyle defines how a prompt is rendered. Looking at the most prompt\nthemes out there, we identified 4 types. All of these require a different configuration and depending on the look\nyou want to achieve you might need to understand/use them all.\n\n### Powerline\n\nWhat started it all for us. Makes use of a single symbol (`powerline_symbol`) to separate the segments. It takes the\nbackground color of the previous segment (or transparent if none) and the foreground of the current one (or transparent\nif we're at the last segment). Expects segments to have a colored background, else there little use for this one.\n\nWhen you see black triangles (or other characters depending on the `powerline_symbol` you use) at the start of a segment,\nyou can set `leading_powerline_symbol` to the \"opening\" version of the `powerline_symbol`.\nThis will not use the inverted ANSI hack we have in place as that's not supported in every terminal. You might need to tweak\nyour font settings to get the best alignment.\n\n:::warning Git Bash\nThe `powerline` style has issues in Git Bash due to the icons width being incorrectly calculated, rendering\nthe prompt broken when typing long commands or searching the history.\n\nThe following prompt configuration has the same problem:\n\n```bash\nexport PS1=\" \"\n```\n\n:::\n\n### Plain\n\nSimple. Colored text on a transparent background. Make sure to set `foreground` for maximum enjoyment.\n\n### Diamond\n\nWhile Powerline works great with a single symbol, sometimes you want a segment to have a different start and end symbol.\nJust like a diamond: `< my segment text >`. The difference between this and plain is that the diamond symbols take the\nsegment background as their foreground color.\n\n### Accordion\n\nSame as Powerline except that it will display even when disabled, but without text. That way it seems\nas if the segment is not expanded, just like an accordion.\n\n## Options\n\nThe `options` attribute allows you to customize the behavior and appearance of a segment beyond the default settings.\nThese options can be anything from feature flags, configuration or additional styling details that will only apply to the segment in question.\nTo understand the available options for a particular segment, refer to its corresponding documentation section where each option is explained in detail.\n\n## Cache\n\nThe cache property allows you to control how often a segment is refreshed. This is useful when a segment is slow to\ngenerate or when you want to avoid fetching information too often. The cache property is an object with the following\nproperties:\n\n| Name       | Type     | Description                                                                                                                                                                                                                       |\n| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `duration` | `string` | the duration for which the segment will be cached. The duration is a string in the format `1h2m3s`. The duration is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none` |\n| `strategy` | `string` | the strategy to use to identify if we should show the segment's cache value. See below for more information on strategy                                                                                                           |\n\n<Config\n  data={{\n    cache: {\n      duration: \"1h\",\n      strategy: \"folder\",\n    },\n  }}\n/>\n\n### Strategy\n\n#### Session\n\nThe session strategy will cache the segment based on the current shell session. Use this for segments you want to display at all times\nbut don't want to refresh too often.\n\n#### Folder\n\nThe folder strategy will cache the segment based on the current working directory. It will cache a separate value for each\ndirectory. This is useful when you for example work with language segments, or source control segments. The source control\nsegments understand repository context in this case, so the same segment cache value is used when in a git repository,\nregardless of the folder you're in.\n\n#### Device\n\nThe device strategy will cache the segment based on the current device. This means that the same cache value is used\nregardless of the folder or shell session. Use this for segments that are slow to generate but don't change often,\nlike system information segments.\n\n## Include / Exclude Folders\n\nSometimes you might want to have a segment only rendered in certain folders. If `include_folders` is specified,\nthe segment will only be rendered when in one of those locations. If `exclude_folders` is specified, the segment\nwill not be rendered when in one of the excluded locations.\n\n<Config\n  data={{\n    include_folders: [\"/Users/posh/Projects\"],\n  }}\n/>\n\n<Config\n  data={{\n    exclude_folders: [\"/Users/posh/Projects\"],\n  }}\n/>\n\nThe strings specified in these properties are evaluated as [regular expressions][regex]. You\ncan use any valid regular expression construct, but the regular expression must match the **ENTIRE** directory\nname. The following will match `/Users/posh/Projects/Foo` but not `/home/Users/posh/Projects/Foo`.\n\n<Config\n  data={{\n    include_folders: [\"/Users/posh/Projects/.*\"],\n  }}\n/>\n\nYou can also combine these properties:\n\n<Config\n  data={{\n    include_folders: [\"/Users/posh/Projects/.*\"],\n    exclude_folders: [\"/Users/posh/Projects/secret-project.*\"],\n  }}\n/>\n\n:::info\n\n- Oh My Posh will accept both `/` and `\\` as path separators for a folder and will match regardless of which\n  is used by the current operating system.\n- Because the strings are evaluated as regular expressions, if you want to use a backslash (`\\`) in a Windows\n  directory name, you need to specify it as double backslashes, and if using JSON format you should escape it as `\\\\\\\\`.\n- The character `~` at the start of a specified folder will match the user's home directory.\n- The comparison is case-insensitive on Windows and macOS, but case-sensitive on other operating systems.\n\nThis means that for user Bill, who has a user account `Bill` on Windows and `bill` on Linux, `~/Foo` might match\n`C:\\Users\\Bill\\Foo` or `C:\\Users\\Bill\\foo` on Windows but only `/home/bill/Foo` on Linux.\n:::\n\n## Index\n\nThe index of the segment in the configuration. This is used to [override] a specific segment in a base configuration.\nThis is a 1-based index, so the first segment has an index of `1`.\n\n## Hiding segments\n\n### Conditionally\n\nTo hide a whole segment including the leading and trailing symbol based on a [template][templates], the template must\n**evaluate to an empty string**. This can be achieved with conditional statements (`if`). The example below will render\na diamond segment, only if the environment variable `POSH_ENV` is not empty.\n\nOnly spaces are excluded, meaning you can still add line breaks and tabs if that is something you're after.\n\n<Config\n  data={{\n    type: \"text\",\n    style: \"diamond\",\n    leading_diamond: \" \\ue0b6\",\n    trailing_diamond: \"\\ue0b4\",\n    foreground: \"#ffffff\",\n    background: \"#d53c14\",\n    template: \"{{ if .Env.POSH_ENV }} \\uf8c5 {{ .Env.POSH_ENV }} {{ end }}\",\n  }}\n/>\n\n### On the fly\n\nSometimes, you run into a situation where you don't want to see a specific segment but the use-case does not justify\nusing a conditional template. In this case you can use the `oh-my-posh toggle <type>` command to toggle the\nsegment on or off. This works on a **per shell session basis**, meaning that if you toggle a segment off in one instance\nof a shell, it will not disable in the others.\n\nTo list the currently toggled segments, use `oh-my-posh get toggles`.\n\n[segments]: /docs/segments/cli/angular\n[options]: #options\n[style]: #style\n[colors]: /docs/configuration/colors\n[go-text-template]: https://golang.org/pkg/text/template/\n[sprig]: https://masterminds.github.io/sprig/\n[regex]: https://www.regular-expressions.info/tutorial.html\n[templates]: templates.mdx\n[color-templates]: /docs/configuration/colors#color-templates\n[cstp]: templates.mdx#cross-segment-template-properties\n[cache]: #cache\n[include-exclude]: #include--exclude-folders\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n[override]: /docs/configuration/general#extends\n[streaming]: /docs/experimental/streaming\n"
  },
  {
    "path": "website/docs/configuration/templates.mdx",
    "content": "---\nid: templates\ntitle: Templates\nsidebar_label: Templates\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport Config from \"@site/src/components/Config.js\";\n\nEvery segment has a `template` property to tweak the text that is displayed.\nUnder the hood, this uses go's [text/template][go-text-template] feature extended with [sprig][sprig] and\noffers a few standard properties to work with.\n\n## Global properties\n\nThese properties can be used anywhere, in any segment. If a segment contains a property with the same name,\nthe segment property value will be used instead. In case you want to use the global property, you can prefix\nit with `.$` to reference it directly.\n\n| Name            | Type                  | Description                                                                      |\n| --------------- | --------------------- | -------------------------------------------------------------------------------- |\n| `.Root`         | `boolean`             | is the current user root/admin or not                                            |\n| `.PWD`          | `string`              | the current working directory (`~` for `$HOME`)                                  |\n| `.AbsolutePWD`  | `string`              | the current working directory (unaltered)                                        |\n| `.PSWD`         | `string`              | the current non-filesystem working directory in PowerShell                       |\n| `.Folder`       | `string`              | the current working folder                                                       |\n| `.Shell`        | `string`              | the current shell name. The value may be overriden by [`maps.shell_name`][maps]. |\n| `.ShellVersion` | `string`              | the current shell version                                                        |\n| `.SHLVL`        | `int`                 | the current shell level                                                          |\n| `.UserName`     | `string`              | the current user name                                                            |\n| `.HostName`     | `string`              | the host name                                                                    |\n| `.Code`         | `int`                 | the last exit code                                                               |\n| `.Jobs`         | `int`                 | number of background jobs (only available for zsh, PowerShell, and Nushell)      |\n| `.OS`           | `string`              | the operating system                                                             |\n| `.WSL`          | `boolean`             | in WSL yes/no                                                                    |\n| `.Templates`    | `string`              | the [templates][templates] result                                                |\n| `.PromptCount`  | `int`                 | the prompt counter, increments with 1 for every prompt invocation                |\n| `.Version`      | `string`              | the Oh My Posh version                                                           |\n| `.Segment`      | [`Segment`](#segment) | the current segment's metadata                                                   |\n\n### Segment\n\n| Name             | Type     | Description                               |\n| ---------------- | -------- | ----------------------------------------- |\n| `.Segment.Index` | `int`    | the current segment's index (as rendered) |\n| `.Segment.Text`  | `string` | the segment's rendered text               |\n\n## Environment variables\n\n| Name           | Type     | Description                                                               |\n| -------------- | -------- | ------------------------------------------------------------------------- |\n| `.Env.VarName` | `string` | Any environment variable where `VarName` is the environment variable name |\n\n:::tip\nFor the shells below, you can override a function to execute some logic before the prompt is rendered.\nThis can be used to for example populate an environment variable with a specific context.\n\n<Tabs\n  queryString=\"shell\"\n  defaultValue=\"powershell\"\n  groupId=\"shell\"\n  values={[\n    { label: 'powershell', value: 'powershell', },\n    { label: 'zsh', value: 'zsh', },\n    { label: 'bash', value: 'bash', },\n    { label: 'fish', value: 'fish', },\n    { label: 'nu', value: 'nu', },\n  ]\n}>\n<TabItem value=\"powershell\">\n\n```powershell\nfunction Set-EnvVar([bool]$originalStatus) {\n    $env:POSH=$(Get-Date)\n}\nNew-Alias -Name 'Set-PoshContext' -Value 'Set-EnvVar' -Scope Global -Force\n```\n\n</TabItem>\n<TabItem value=\"zsh\">\n\n```bash\nfunction set_poshcontext() {\n    export POSH=$(date)\n}\n```\n\n</TabItem>\n<TabItem value=\"bash\">\n\n```bash\nfunction set_poshcontext() {\n    export POSH=$(date)\n}\n```\n\n</TabItem>\n<TabItem value=\"fish\">\n\n```shell\nfunction set_poshcontext\n  set --export POSH $(date)\nend\n```\n\n</TabItem>\n<TabItem value=\"nu\">\n\n```bash\n$env.SET_POSHCONTEXT = {\n\t$env.POSH = ( date now );\n}\n```\n\n</TabItem>\n</Tabs>\n\n:::\n\n## Config variables\n\n| Name           | Type  | Description                                              |\n| -------------- | ----- | -------------------------------------------------------- |\n| `.Var.VarName` | `any` | Any config variable where `VarName` is the variable name |\n\n### Example\n\n<Config\n  data={{\n    version: 4,\n    var: {\n      Hello: \"hello\",\n      World: \"world\",\n    },\n    blocks: [\n      {\n        type: \"prompt\",\n        alignment: \"left\",\n        segments: [\n          {\n            type: \"text\",\n            style: \"plain\",\n            foreground: \"p:white\",\n            template: \"{{ .Var.Hello }} {{ .Var.World }} \",\n          },\n        ],\n      },\n    ],\n  }}\n  metastring={{\n    json: \"{3-6,16}\",\n    yaml: \"{2-4,12}\",\n    toml: \"{3-5,15}\",\n  }}\n/>\n\n## Template logic\n\n| Template                                                             | Description                                                                                                                                                                                                                                                                                                     |\n| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `{{.}}`                                                              | Root element.                                                                                                                                                                                                                                                                                                   |\n| `{{.Var}}`                                                           | Variable in a struct, where Var is a variable.                                                                                                                                                                                                                                                                  |\n| `{{- .Var -}}`                                                       | Remove extra white space surrounding the .Var variable and remove the newline. Either side is fine too.                                                                                                                                                                                                         |\n| `{{ $planet := \"Earth\"}}`                                            | `{{ $planet }}` Store a value in a custom variable to reference later. Note that .$ is used to reference the global/parent context, like in the full example below with $.                                                                                                                                      |\n| `Hi {{if .Name}} {{.Name}} {{else}} visitor {{end}}`                 | If-else statement. If will evaluate whether or not the argument is empty. Using the elseif conditional is also an option. The not negation is available too.                                                                                                                                                    |\n| `{{if and .Arg1 .Arg2}} both complete. {{else}} incomplete. {{end}}` | The and function compares multiple arguments to return the boolean AND (if arg1 then arg2 else arg1). Both arguments are evaluated. The or function compares multiple arguments to return the boolean OR. Similar to if arg1 then arg1 else arg2, so arg2 will never be evaluated if arg1 is false (not empty). |\n| `{{with .Var}} {{end}}`                                              | With statement, where Var is a variable. It skips the block if the variable is absent.                                                                                                                                                                                                                          |\n| `{{range .Array}} {{end}}`                                           | Range statement, where Array is an array, slice, map, or channel.                                                                                                                                                                                                                                               |\n| `{{ lt 3 4 }}`                                                       | This lt comparison function evaluates to true since 3 is less than 4 (other boolean operators: eq, ne, lt, le, gt, ge).                                                                                                                                                                                         |\n\n## Helper functions\n\n### Sprig\n\nOh My Posh has all [sprig][sprig] functions included, meaning you can do operations on strings, paths and a lot of other\nmanipulations straight from your template. Have a look at [their documentation][sprig] for available options and how to\nuse them.\n\n### Custom\n\n| Template                                                           | Description                                                                                                                |\n| ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |\n| `{{ url .UpstreamIcon .UpstreamURL }}`                             | Create an `OSC8` hyperlink to a website to open your default browser (needs terminal [support][terminal-list-hyperlinks]). |\n| `{{ path .Path .Location }}`                                       | Create an `OSC8` file link to a folder to open your file explorer (needs terminal [support][terminal-list-hyperlinks]).    |\n| `{{ secondsRound 3600 }}`                                          | Round seconds to a time indication. In this case the output is `1h`.                                                       |\n| `{{ if glob \"*.go\" }}OK{{ else }}NOK{{ end }}`                     | Exposes [filepath.Glob][glob] as a boolean template function.                                                              |\n| `{{ if matchP \".*\\\\.Repo$\" .Path }}Repo{{ else }}No Repo{{ end }}` | Exposes [regexp.MatchString][regexpms] as a boolean template function.                                                     |\n| `{{ replaceP \"c.t\" \"cut code cat\" \"dog\" }}`                        | Exposes [regexp.ReplaceAllString][regexpra] as a string template function.                                                 |\n| <code>\\{\\{ .Code &vert; hresult \\}\\}</code>                        | Transform a status code to its HRESULT value for easy troubleshooting. For example `-1978335212` becomes `0x8A150014`.     |\n| `{{ readFile \".version.json\" }}`                                   | Read a file in the current directory. Returns a string.                                                                    |\n| `{{ random (list \\\"a\\\" 2 .MyThirdItem) }}`                         | Selects a random element from a list. The list can be an array or slice containing any types (use sprig's `list`).         |\n\n## Cross segment template properties\n\nTo use another segment's template properties in a template, you can make use of `{{ .Segments.Segment }}`\nin your template where `.Segment` is the name of the segment you want to use with the first letter uppercased.\n\nIf you want to for example use the [git][git] segment's `.UpstreamGone` property in the [status][status] segment, you can\ndo so like this:\n\n<Config\n  data={{\n    template:\n      \" {{ if .Segments.Git.UpstreamGone }}\\ueb05{{ else if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} \",\n  }}\n/>\n\n:::caution\nFor this to work, the segment you refer to needs to be in your config. The above example won't work if\nyour config does not contain a git segment as Oh My Posh only populates the properties when it needs to.\n:::\n\n:::tip\nIf you have two identical segments for a different purpose, you can make use of the `alias` property on the segment\nto distinct between both.\n:::\n\n<Config\n  data={{\n    segments: [\n      {\n        type: \"git\",\n        alias: \"GitMain\",\n        style: \"plain\",\n        foreground: \"#ffffff\",\n        options: {\n          branch_icon: \"\",\n        },\n      },\n      {\n        type: \"git\",\n        alias: \"GitSecondary\",\n        style: \"plain\",\n        foreground: \"#ffffff\",\n        options: {\n          branch_icon: \"\",\n        },\n      },\n      {\n        type: \"text\",\n        style: \"plain\",\n        foreground: \"#ffffff\",\n        template: \"{{ .Segments.GitMain.HEAD }} - {{ .Segments.GitSecondary.HEAD }}\",\n      },\n    ],\n  }}\n/>\n\nIf you want to know if a specific segment is active, you can use the `.Segments.Contains` function, for example:\n\n<Config\n  data={{\n    template:\n      '{{ if .Segments.Contains \"Git\" }}\\ueb05{{ else if gt .Code 0 }}\\uf00d{{ else }}\\uf00c{{ end }} ',\n  }}\n/>\n\n## Text decoration\n\nYou can make use of the following syntax to decorate text:\n\n| Syntax                 | Description                           |\n| ---------------------- | ------------------------------------- |\n| `<b>bold</b>`          | `bold` as bold text                   |\n| `<u>underline</u>`     | `underline` as underlined text        |\n| `<o>overline</o>`      | `overline` as overlined text          |\n| `<i>italic</i>`        | `italic` as italic text               |\n| `<s>strikethrough</s>` | `strikethrough` as strikethrough text |\n| `<d>dimmed</d>`        | `dimmed` as dimmed text               |\n| `<f>blink</f>`         | `blink` as blinking (flashing) text   |\n| `<r>reversed</r>`      | `reversed` as reversed text           |\n\nThis can be used in templates and icons/text inside your config.\n\n[terminal-list-hyperlinks]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda\n[go-text-template]: https://pkg.go.dev/text/template\n[sprig]: https://masterminds.github.io/sprig/\n[glob]: https://pkg.go.dev/path/filepath#Glob\n[git]: /docs/segments/scm/git\n[maps]: /docs/configuration/general#maps\n[status]: /docs/segments/system/status\n[templates]: /docs/configuration/segment\n[regexpms]: https://pkg.go.dev/regexp#Regexp.MatchString\n[regexpra]: https://pkg.go.dev/regexp#Regexp.ReplaceAllString\n"
  },
  {
    "path": "website/docs/configuration/title.mdx",
    "content": "---\nid: title\ntitle: Console title\nsidebar_label: Console title\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    console_title_template:\n      \"{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}\",\n  }}\n/>\n\n## Console Title Template\n\nThe following examples illustrate possible contents for `console_title_template`, provided\nthe current working directory is `/usr/home/omp` and the shell is `zsh`.\n\nTo learn more about templates and their possibilities, have a look at the [template][templates] section.\n\n```json\n{\n  \"console_title_template\": \"{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}\",\n  // outputs:\n  // when root == false: omp :: zsh\n  // when root == true: omp :: root :: zsh\n  \"console_title_template\": \"{{.Folder}}\", // outputs: omp\n  \"console_title_template\": \"{{.Shell}} in {{.PWD}}\", // outputs: zsh in /usr/home/omp\n  \"console_title_template\": \"{{.UserName}}@{{.HostName}} {{.Shell}} in {{.PWD}}\", // outputs: MyUser@MyMachine zsh in /usr/home/omp\n  \"console_title_template\": \"{{.Env.USERDOMAIN}} {{.Shell}} in {{.PWD}}\" // outputs: MyCompany zsh in /usr/home/omp\n}\n```\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/configuration/tooltips.mdx",
    "content": "---\nid: tooltips\ntitle: Tooltips\nsidebar_label: Tooltips\n---\n\n:::info\nDue to limitations (or not having found a way just yet), this feature only works in `fish`, `zsh`, `powershell`\n(`ConstrainedLanguage` mode unsupported) and `cmd` (as of [Clink][clink] v1.2.46+) for the time being.\n:::\n\n![Tooltip Demo](/img/posh-tooltip.gif)\n\nTooltips are segments that are rendered as a right-aligned prompt while you're typing certain keywords.\nThey behave similarly to the other segments when it comes to how and when they are shown so you can tweak\nthem to act and look like you want. The key difference is that they can be invoked using `tips` which are the\ncommands you are typing. Due to the possibility of the use of an alias, you can define for which keyword\nthe segment should be rendered.\n\n## Configuration\n\nYou need to extend or create a custom theme with your tooltips. For example:\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    blocks: [],\n    tooltips_action: \"replace\",\n    tooltips: [\n      {\n        type: \"git\",\n        tips: [\"git\", \"g\"],\n        style: \"diamond\",\n        foreground: \"#193549\",\n        background: \"#fffb38\",\n        leading_diamond: \"\\ue0b6\",\n        trailing_diamond: \"\\ue0b4\",\n        template:\n          \"{{ .HEAD }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}\",\n        options: {\n          fetch_status: true,\n          fetch_upstream_icon: true,\n        },\n      },\n    ],\n  }}\n/>\n\nThis configuration will render a right-aligned git segment when you type `git` or `g` followed by a space.\nA tip should not include any spaces. Keep in mind that this is a blocking call, meaning that if the segment renders slow,\nyou can't type until it's visible. Optimizations in this space are being explored.\n\nNote that you can also define multiple tooltips for the same tip to compose tooltips for individual commands. For example,\nthis configuration will render the AWS profile as well as the Azure subscription information when you type `terraform`\nfollowed by a space.\n\n<Config\n  data={{\n    blocks: [],\n    tooltips: [\n      {\n        type: \"aws\",\n        tips: [\"aws\", \"terraform\"],\n        style: \"plain\",\n        foreground: \"#e0af68\",\n        template: \"\\uf0e0f {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\",\n      },\n      {\n        type: \"az\",\n        tips: [\"az\", \"terraform\"],\n        style: \"plain\",\n        foreground: \"#b4f9f8\",\n        template: \"\\uebd8 {{ .Name }}\",\n      },\n    ],\n  }}\n/>\n\n## Tooltips action\n\nYou can configure the tooltips to display in extension to the current rprompt (if any) or replace it (default behavior).\nYou can do this by setting the `tooltips_action` property in your configuration. The possible values are:\n\n- `replace`: Replaces the current rprompt with the tooltips. This is the default behavior.\n- `extend`: Appends the tooltips to the current rprompt.\n- `prepend`: Prepends the tooltips to the current rprompt.\n\nYou can set this property in your configuration like so:\n\n<Config\n  data={{\n    blocks: [],\n    tooltips_action: \"extend\",\n    tooltips: [],\n  }}\n/>\n\n[clink]: https://chrisant996.github.io/clink/\n"
  },
  {
    "path": "website/docs/configuration/transient.mdx",
    "content": "---\nid: transient\ntitle: Transient prompt\nsidebar_label: Transient prompt\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport Config from \"@site/src/components/Config.js\";\n\n:::info\nThis feature only works in `nu`, `fish`, `zsh`, `powershell` (`ConstrainedLanguage` mode unsupported), bash (with [ble.sh]) and `cmd` for the time being.\n:::\n\nTransient prompt, when enabled, replaces the prompt with a simpler one to allow more screen real estate.\nYou can use go [text/template][go-text-template] templates extended with [sprig] to enrich the text.\nAll [template][templates] functionality is available, even reusing [cross segment template properties][cstp] from\nthe previous primary prompt run.\n\nTypically, your prompt will simply leave the prompt on the screen when you execute a command (or press enter) like so:\n\n![Before Transient](/img/transient-before.gif)\n\nBy enabling Transient Prompt, you can replace the prompt with some other content for a cleaner console as shown here:\n\n![After Transient](/img/transient-after.gif)\n\n## Configuration\n\nYou need to extend or create a custom theme with your transient prompt. For example:\n\n<Config\n  data={{\n    transient_prompt: {\n      background: \"transparent\",\n      foreground: \"#ffffff\",\n      template: \"{{ .Shell }}> \",\n    },\n  }}\n/>\n\n## Options\n\n| Name                   | Type      | Description                                                                                                                                    |\n| ---------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |\n| `foreground`           | `string`  | [color][colors]                                                                                                                                |\n| `foreground_templates` | `array`   | [color templates][color-templates]                                                                                                             |\n| `background`           | `string`  | [color][colors]                                                                                                                                |\n| `background_templates` | `array`   | [color templates][color-templates]                                                                                                             |\n| `template`             | `string`  | a go [text/template][go-text-template] template extended with [sprig][sprig] utilizing the properties below - defaults to `{{ .Shell }}> `     |\n| `filler`               | `string`  | when you want to create a line with a repeated set of characters spanning the width of the terminal. Will be added _after_ the `template` text |\n| `newline`              | `boolean` | add a newline before the prompt                                                                                                                |\n\n## Enable the feature\n\nOh My posh handles enabling the feature automatically for all shells except `cmd` when the config contains a\ntransient prompt configuration. For `cmd`, you can run the command below once to enable the feature permanently:\n\n```shell\nclink set prompt.transient always\n```\n\n[ble.sh]: https://github.com/akinomyoga/ble.sh\n[colors]: /docs/configuration/colors\n[go-text-template]: https://golang.org/pkg/text/template/\n[sprig]: https://masterminds.github.io/sprig/\n[templates]: /docs/configuration/templates\n[color-templates]: /docs/configuration/colors#color-templates\n[cstp]: /docs/configuration/templates#cross-segment-template-properties\n"
  },
  {
    "path": "website/docs/contributing/git.mdx",
    "content": "---\nid: git\ntitle: Git commands for contributors\nsidebar_label: Git Commands\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\nWhile we're mostly used to working with source control, working with a fork and making sure\nwe can merge swiftly brings some additional challenges. This page aims to help you out with the things you might\nget asked to do, but which may be outside of your comfort zone.\n\nSit back, relax and bring your towel.\n\nIf you're not comfortable using git from the CLI, we recommend [GitKraken][kraken]. It's the best cross platform git tool and\nwe've added instructions on how to use it below as well.\n\n## I didn't stick to the conventional commit guidelines\n\n<Tabs\n  defaultValue=\"kraken\"\n  groupId=\"git\"\n  values={[\n    { label: 'GitKraken', value: 'kraken', },\n    { label: 'CLI', value: 'cli', },\n  ]\n}>\n<TabItem value=\"kraken\">\n\nOpen your oh-my-posh repo inside GitKraken and right click the commit you want to reword in the graph overview.\nSelect `Edit commit message`, reword it to respect the conventional commit guidelines and press `Update message`.\n\nClick Push on the top of the screen and select `Force Push` to bring the changes to the Pull Request.\n\n</TabItem>\n<TabItem value=\"cli\">\n\n**I only have 1 commit**\n\nTo reword the last commit, we can make use of git's `--amend` switch to add something to our latest commit (code, changes, rewording).\nUse the following commands to rephrase the last commit and get that change merged!\n\n```bash\ngit commit --amend -m \"feat: better worded feature\"`\ngit push --force\n```\n\n**I added more than commit**\n\nIf all of your commits need to go to main because it makes sense to treat these as atomic units, you can use git's interactive rebase\nfunctionality to reword any commit between `main` and your `HEAD`. To start an interactive rebase, type `git rebase -i main`.\n\nThis will open your `$EDITOR` and you can mark the commits you want to reword with `reword` (or `r`) rather than `pick`.\nExiting that file will start the rebase and spawn your `$EDITOR` to alter the commit message for each commit you marked as `reword`.\n\nOnce done, use `git push --force` to bring the changes to the pull request.\n\n:::tip vscode\nThe latest version of vscode has a built-in gui to help you select `reword` or any other action on a commit. Select the right ones and press\nStart Rebase to continue.\n:::\n\n</TabItem>\n</Tabs>\n\n## My branch is out of date with the remote\n\nThis means the main branch of oh-my-posh contains commits your branch does not (could be your main branch, or the branch you created to work on).\nTo remedy this, we need to rebase (add the new commits of oh-my-posh's main branch underneath your new commits) so the pull request can get merged.\n\nThe first thing to do is to add the oh-my-posh codebase as a remote to your local git repository. By default, your fork is a standalone copy\nof oh-my-posh with its own remote on GitHub that's not connected to the oh-my-posh codebase. Forks and Pull Requests are a feature GitHub introduced\non top of git functionality, so we need to mimic that situation ourselves.\n\n\n### Add the remote to your local git repository\n\n<Tabs\n  defaultValue=\"kraken\"\n  groupId=\"git\"\n  values={[\n    { label: 'GitKraken', value: 'kraken', },\n    { label: 'CLI', value: 'cli', },\n  ]\n}>\n<TabItem value=\"kraken\">\n\nHover over `Remote` on the left-hand side, this will show a `+` button. Click it and select GitHub. There you have the ability to select\n`jandedobbeleer/oh-my-posh` and name it `upstream`. GitKraken will fetch the remote and you will see all branches underneath `upstream` as\nyou do for your own branches. Right click `upstream`'s `main` branch and select `Rebase <branch> onto upstream/main`.\n\nClick Push on the top of the screen and select `Force Push` to bring the changes to the Pull Request.\n\n</TabItem>\n<TabItem value=\"cli\">\n\n```bash\ngit remote add upstream git@github.com:JanDeDobbeleer/oh-my-posh.git\ngit fetch upstream\n```\n\n</TabItem>\n</Tabs>\n\n### Rebase your branch onto upstream/main\n\n<Tabs\n  defaultValue=\"kraken\"\n  groupId=\"git\"\n  values={[\n    { label: 'GitKraken', value: 'kraken', },\n    { label: 'CLI', value: 'cli', },\n  ]\n}>\n<TabItem value=\"kraken\">\n\nRight click `upstream`'s `main` branch and select `Rebase <branch> onto upstream/main`. Click Push on the top of the screen and select\n`Force Push` to bring the changes to the Pull Request.\n\n</TabItem>\n<TabItem value=\"cli\">\n\n```bash\ngit rebase upstream/main\ngit push --force\n```\n\n</TabItem>\n</Tabs>\n\n[kraken]: https://www.gitkraken.com/invite/nQmDPR9D\n"
  },
  {
    "path": "website/docs/contributing/plastic.mdx",
    "content": "---\nid: plastic\ntitle: Setup for Plastic SCM testing\nsidebar_label: Plastic SCM testing\n---\n\nWhen changing the `segment_plastic.go` file, you may need to test your changes against an actual instance of\n[Plastic SCM][plastic]. This doc should bring you up to speed with Plastic SCM.\n\nIn the [contributing doc][contributing] there is a section about [dev containers & codespaces][devcontainer].\nYou can set up Plastic SCM inside these as well.\n\n## Server Setup\n\nHere you can find the [official setup instructions][setup-instructions]. I'll describe it in short:\n\n### Installation on Debian or in dev-container\n\nFirst add the repo:\n\n```bash\nsudo apt-get update\nsudo apt-get install -y apt-transport-https\nwget -qO - https://www.plasticscm.com/plasticrepo/stable/debian/Release.key | \\\n  gpg --dearmor | sudo tee /usr/share/keyrings/plasticscm-stable.gpg > /dev/null\necho \"deb [signed-by=/usr/share/keyrings/plasticscm-stable.gpg] \\\n  https://www.plasticscm.com/plasticrepo/stable/debian ./\" | \\\n  sudo tee /etc/apt/sources.list.d/plasticscm-stable.list\nsudo apt-get update\n```\n\nThen install the server: *this might throw an error at the end of the setup **see below***\n\n```bash\nsudo apt-get install -y plasticscm-server-core\n```\n\nThis might show an error while configuring the installed package. In that case the server was not registered as a service.\n**Ignore it!**\n\n### Server configuration\n\nConfiguring the server is done via:\n\n```bash\nsudo /opt/plasticscm5/server/plasticd configure \\\n  --language=en \\\n  --workingmode=NameWorkingMode \\\n  --port=8087 \\\n  --sslport=8088\n```\n\n**Congrats!** Your server is configured. You can find out more in the [official configuration instructions][server-config].\n\n### Run Server\n\nIf your server installed without an error, it was correctly registered as a server and can be started via:\n\n```bash\nsudo service plasticd start\n```\n\nIf not, you need to start it manually (for example inside the dev-container):\n\n```bash\nsudo /opt/plasticscm5/server/plasticd start\n```\n\nThis will lock the current shell until the server process finishes. You might need to open another terminal to continue.\n\nYour Plastic SCM server should be started now.\n\n## Client Setup\n\nPlastic SCM comes, much like git, with a CLI (+ client UI \\[optional\\])\n\n### Installation on Debian or in dev-container\n\nThese are the steps to install the **Plastic SCM CLI** on Debian or in the dev-container:\n\n```bash\nsudo apt-get install -y plasticscm-client-core\n```\n\n### Client configuration\n\nTo connect the client to the server and set up an account run:\n\n```bash\ncm configure \\\n  --language=en \\\n  --workingmode=NameWorkingMode \\\n  --server=localhost \\\n  --port=8087\n```\n\n**Congrats!** Your client should now be connected to your server. You can find out more in the [official configuration instructions][client-config].\n\nYou can test if it worked and display some license info via:\n\n```bash\ncm li\n```\n\n## Testing stuff\n\nNow to the fun part! The server is automatically set up to host a `default` repo with the branch `/main`.\n\nThe Plastic SCM CLI command is: `cm`\n\nIf you ever wonder what you can do with it call:\n\n```bash\ncm showcommands --all\n```\n\n### Creating a local workspace\n\nYou need a local workspace to work with plastic:\n\n```bash\ncd ~\nmkdir dev\ncd dev\ncm wk create workspace workspace rep:default\ncd workspace\ncm status\n```\n\n### Adding files\n\nStart by creating local, private files\n\n```bash\necho \"test\" > myfile.txt\ncm status --all\n```\n\nAdd the file to your local changes\n\n```bash\ncm add myfile.txt\ncm status\n```\n\n**Test hint:** Both `Private` and `Added` files should be counted towards the `Added` property of the `plastic` segment.\n\n### Committing changes\n\nAfter locally adding, changing, moving or deleting files you want to commit them to create a new changeset.\nRun this command to commit all local changes:\n\n```bash\ncm status | cm ci . -c \"my first commit\"\n```\n\n### Undoing local changes\n\nJust in case you don't want or can't commit your local changes, there is an undo command.\nThis will undo all local changes:\n\n```bash\ncm status | cm undo .\n```\n\n### Changing, moving or deleting files\n\nAll these actions are done on the file level. You can run `cm status` to see your actions being tracked by plastic.\nUse the commit method described above to commit your changes.\n\n**Test hint:** All these changes should be counted by the designated property (`Modified`, `Moved`, `Deleted`)\nof the `plastic` segment.\n\n### Branching\n\nAbove the basics of handling the Plastic SCM client are described.\nBut you would want to dive deeper and use branches or labels and merge them.\n\n#### Create a new branch\n\nTo create a new branch based on the latest changeset on branch `/main` call\n\n```bash\ncm br /main/new-branch\n```\n\nHint: To list all branches use\n\n```bash\ncm find branches\n```\n\n#### Set a label to the current changeset\n\nYour workspace will always reflect one specific changeset (see `cm status`). You can set a label on that changeset for\nfast navigation or documentation purposes\n\n```bash\ncm label mk \"BL0001\"\n```\n\nHint: To list all labels use\n\n```bash\ncm find labels\n```\n\n#### Switch your local workspace to a branch\n\nTo switch to a branch use\n\n```bash\ncm switch /main/new-branch\ncm status\n```\n\n**Test Hint:** the branch name should be reflected in the `Selector` property of the `plastic` segment\n\n#### Switch to a changeset\n\nEach commit gets a unique changeset number. You can switch to these via\n\n```bash\ncm switch cs:1\n```\n\n**Test Hint:** the changeset should be reflected in the `Selector` property of the `plastic` segment\n\n#### Switch to a label\n\nYou can also switch to a label via\n\n```bash\ncm switch BL00001\n```\n\n**Test Hint:** the label should be reflected in the `Selector` property of the `plastic` segment\n\n#### Merge a branch\n\nTo merge a branch you have to switch to the *destination* branch of the merge. After that you can merge another branch via\n\n```bash\ncm switch /main\ncm merge /main/new-branch --merge\ncm status\n```\n\nHint: This will only prepare the merge locally. You will have to commit the changes to complete the merge!\n\n**Test Hint:** A pending merge should be reflected in the `MergePending` property of the `plastic` segment\n\n#### Cherry-pick merge\n\nWhile the merge above will merge all changes from a branch (and his parents), there is a cherry-pick merge,\nwhich will merge only the changes of one single changeset\n\n```bach\ncm merge cs:8 --merge --cherrypicking\n```\n\nHint: This will only prepare the merge locally. You will have to commit the changes to complete the merge!\n\n**Test Hint:** A pending cherry-pick merge should be reflected in the `MergePending` property of the `plastic` segment\n\n#### Merge conflicts\n\nThere are multiple causes for conflicts while merging\n\n##### Evil Twin\n\nThis happens when a merge is performed where two files with the same name were added on both the source and destination branch.\n\n```bash\ncm br mk /main/sub-branch\ncm switch /main/sub-branch\necho \"1\" > twin.txt\ncm add twin.txt\ncm ci twin.txt\n\ncm switch /main\necho \"2\" > twin.txt\ncm add twin.txt\ncm ci twin.txt\n\ncm merge /main/sub-branch --merge\n```\n\nHint: this will prompt you to directly resolve the conflict\n\n##### Changed on both sides\n\nThis happens when a merge is performed where a file was changed on both sides: source and destination\n\n```bash\ncm switch /main\necho \"base\" > file.txt\ncm add file.txt\ncm ci file.txt\n\ncm br mk /main/test\n\necho \"on main\" > file.txt\ncm ci file.txt\n\ncm switch /main/test\necho \"on test\" > file.txt\ncm ci file.txt\n\ncm switch /main\ncm merge /main/test --merge\n```\n\nHint: this will try to open `gtkmergetool` which will fail inside the dev-container!\n\n##### Changed vs. deleted file\n\nThis happens when a merge is performed where a file was modified on one side and deleted on the other side of the merge\n\n```bash\ncm switch /main\necho \"base\" > deleteme.txt\ncm add deleteme.txt\ncm ci deleteme.txt\n\ncm br mk /main/del\n\nrm deleteme.txt\ncm ci --all\n\ncm switch /main/del\necho \"on del\" > deleteme.txt\ncm ci deleteme.txt\n\ncm switch /main\ncm merge /main/del --merge\n```\n\nHint: This will prompt you to directly resolve the merge conflict\n\n[plastic]: https://www.plasticscm.com/\n[setup-instructions]: https://docs.unity.com/en-us/unity-version-control/install-uvcs-on-linux#debian\n[server-config]: https://docs.unity.com/en-us/unity-version-control/uvcs-on-prem/server-configuration\n[client-config]: https://docs.unity.com/en-us/unity-version-control/uvcs-on-prem/client-configuration\n[contributing]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md\n[devcontainer]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md#codespaces--devcontainer-development-environment\n"
  },
  {
    "path": "website/docs/contributing/segment.mdx",
    "content": "---\nid: segment\ntitle: Add Segment\nsidebar_label: Add Segment\n---\n\nAdding a new segment to Oh My Posh involves several steps to ensure proper integration. This guide walks you through creating a complete segment with all necessary files and registrations.\n\n## Planning Your Segment\n\nBefore coding, define these key properties:\n\n- **Segment ID**: A kebab-case identifier used in configs (e.g., `new-feature`)\n- **Go Type Name**: PascalCase struct name for the code (e.g., `NewFeature`)\n- **Category**: Choose from `cli`, `cloud`, `health`, `languages`, `music`, `scm`, `system`, or `web`\n- **Description**: A clear one-line explanation of what the segment does\n- **Properties**: List of configurable properties with types and defaults\n- **Template**: Default template string (e.g., `{{ .Text }}`)\n\n## Automated Setup (VS Code)\n\nIf you're using VS Code, you can use the automated segment creation command in VS Code Chat:\n\n1. Open VS Code Chat (use the Chat icon in the sidebar or Command Palette: \"Chat: Focus on Chat View\")\n2. Type `/segment` and follow the prompts\n3. Provide your segment details when requested\n4. The command will automatically create all necessary files and registrations\n\nThis automated approach ensures all files are created correctly with proper naming conventions and alphabetical ordering. If you prefer to create the segment manually or want to understand the process, continue with the manual steps below.\n\n## Manual Setup Steps\n\n## Step 1: Create the Go Implementation\n\nCreate a new file in `./src/segments/` named after your segment ID: `new_feature.go`.\n\n```go\npackage segments\n\nimport (\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n)\n\ntype NewFeature struct {\n\tBase\n\n\t// Fields that will be available in your template\n\tText string\n}\n\n// Define constants for each configurable property\nconst (\n\t// EnableNewThing enables the new functionality\n\tEnableNewThing options.Property = \"enable_new_thing\"\n\t// CustomText sets custom display text\n\tCustomText options.Property = \"custom_text\"\n)\n\nfunc (n *NewFeature) Enabled() bool {\n\t// Set up data for the template using property values\n\tn.Text = n.props.GetString(CustomText, \"default value\")\n\n\t// Return true if the segment should be displayed\n\t// You can add logic here to determine if the segment is relevant\n\treturn true\n}\n\nfunc (n *NewFeature) Template() string {\n\treturn \"{{ .Text }}\"\n}\n```\n\n**Key Guidelines:**\n\n- Use UTF32 representation for icons (e.g., `\"\\uEFF1\"`) instead of the actual icons\n- Find icon codes at [Nerd Fonts Cheat Sheet][nf-icons]\n- Keep the logic in `Enabled()` focused on data preparation and visibility determination\n\n## Step 2: Register Your Segment\n\nEdit `src/config/segment_types.go` to register your new segment:\n\n### Add Gob Registration\n\nIn the `init()` function, add your segment to the gob registry (maintain alphabetical order):\n\n```go\ngob.Register(&segments.NewFeature{})\n```\n\n### Add Segment Constant\n\nAdd a constant for your segment type (maintain alphabetical order):\n\n```go\n// NEWFEATURE displays new feature information\nNEWFEATURE SegmentType = \"new-feature\"\n```\n\n### Add to Segments Map\n\nRegister your segment in the `Segments` map (maintain alphabetical order):\n\n```go\nNEWFEATURE: func() SegmentWriter { return &segments.NewFeature{} },\n```\n\n## Step 3: Create Documentation\n\nCreate documentation at `website/docs/segments/[category]/[segment-id].mdx`:\n\n```mdx\n---\nid: new-feature\ntitle: New Feature\nsidebar_label: New Feature\n---\n\n## What\n\nDisplays information about the new feature in your environment.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"new-feature\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    options: {\n      enable_new_thing: true,\n      custom_text: \"Hello World\",\n    },\n  }}\n/>\n\n## Options\n\n| Name               | Type      | Default | Description                   |\n| ------------------ | --------- | ------- | ----------------------------- |\n| `enable_new_thing` | `boolean` | `false` | Enables the new functionality |\n| `custom_text`      | `string`  | `\"\"`    | Custom text to display        |\n```\n\n## Step 4: Update Sidebar Navigation\n\nEdit `website/sidebars.js` and add your documentation to the appropriate category (maintain alphabetical order):\n\n```javascript\n{\n  type: \"category\",\n  label: \"🖥️ System\", // or appropriate category\n  collapsed: true,\n  items: [\n    // ... other segments\n    \"segments/system/new-feature\",\n    // ... more segments\n  ]\n}\n```\n\n## Step 5: Add JSON Schema Definition\n\nUpdate `themes/schema.json` in two places:\n\n### Add to Type Enum\n\nIn the segment type enum, add your segment ID (maintain alphabetical order):\n\n```json\n{\n  \"enum\": [\n    \"angular\",\n    // ... other types\n    \"new-feature\"\n    // ... more types\n  ]\n}\n```\n\n### Add Schema Definition\n\nIn the `allOf` array, add your segment's property schema (maintain alphabetical order):\n\n```json\n{\n  \"if\": {\n    \"properties\": {\n      \"type\": { \"const\": \"new-feature\" }\n    }\n  },\n  \"then\": {\n    \"title\": \"New Feature Segment\",\n    \"description\": \"https://ohmyposh.dev/docs/segments/system/new-feature\",\n    \"properties\": {\n      \"options\": {\n        \"properties\": {\n          \"enable_new_thing\": {\n            \"type\": \"boolean\",\n            \"title\": \"Enable New Thing\",\n            \"description\": \"Enables the new functionality\",\n            \"default\": false\n          },\n          \"custom_text\": {\n            \"type\": \"string\",\n            \"title\": \"Custom Text\",\n            \"description\": \"Custom text to display\",\n            \"default\": \"\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n## Step 6: Add Tests\n\nCreate a test file `src/segments/new_feature_test.go` using table-driven tests:\n\n```go\npackage segments\n\nimport (\n\t\"testing\"\n\n\t\"github.com/jandedobbeleer/oh-my-posh/src/segments/options\"\n\t\"github.com/jandedobbeleer/oh-my-posh/src/runtime/mock\"\n)\n\nfunc TestNewFeature(t *testing.T) {\n\tcases := []struct {\n\t\tCase     string\n\t\tTemplate string\n\t\tCustomText string\n\t\tExpected string\n\t}{\n\t\t{Case: \"default\", CustomText: \"\", Expected: \"\"},\n\t\t{Case: \"custom text\", CustomText: \"Hello\", Expected: \"Hello\"},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.Case, func(t *testing.T) {\n\t\t\tenv := &mock.Environment{}\n\t\t\tprops := options.Map{\n\t\t\t\tCustomText: tc.CustomText,\n\t\t\t}\n\n\t\t\tsegment := &NewFeature{}\n\t\t\tsegment.Init(props, env)\n\n\t\t\tif !segment.Enabled() {\n\t\t\t\tt.Error(\"Expected segment to be enabled\")\n\t\t\t}\n\n\t\t\tif segment.Text != tc.Expected {\n\t\t\t\tt.Errorf(\"Expected %s, got %s\", tc.Expected, segment.Text)\n\t\t\t}\n\t\t})\n\t}\n}\n```\n\nLook at [existing segment tests][tests] for more complex examples and inspiration.\n\n## Step 7: Build and Test\n\nValidate your implementation by building the project:\n\n```shell\ngo build -v\n```\n\nRun your specific tests:\n\n```shell\ngo test ./src/segments/new_feature_test.go\n```\n\n## Important Guidelines\n\n### File Organization\n\n- **Segment files**: `src/segments/[segment_id].go`\n- **Test files**: `src/segments/[segment_id]_test.go`\n- **Documentation**: `website/docs/segments/[category]/[segment-id].mdx`### Alphabetical Ordering\n  Maintain alphabetical order in:\n- `init()` gob registrations in `segment_types.go`\n- Segment type constants in `segment_types.go`\n- Segments map entries in `segment_types.go`\n- Schema type enum in `themes/schema.json`\n- Schema `allOf` definitions in `themes/schema.json`\n- Sidebar navigation items in `sidebars.js`\n\n### Code Quality\n\n- Use meaningful property names and constants\n- Include descriptive comments for options\n- Keep `Enabled()` logic focused and efficient\n- Use UTF32 codes for icons, not the actual icons\n- Follow Go naming conventions (PascalCase for exported items)\n\n### Documentation Standards\n\n- Use `.mdx` extension for documentation files\n- Include complete property tables with types, descriptions, and defaults\n- Provide realistic sample configurations\n- Keep line lengths under 120 characters\n- Use proper headings and formatting\n\n## Resources\n\n- [Nerd Fonts Cheat Sheet][nf-icons] - Find icon UTF32 codes\n- [Existing Tests][tests] - Examples for test patterns\n- [Table-Driven Tests][tables] - Go testing best practices\n\n## Create a Pull Request\n\nOnce you've completed all steps:\n\n1. **Verify everything builds**: `go build -v`\n2. **Run tests**: `go test ./src/segments/[your_segment]_test.go`\n3. **Check formatting**: Ensure your code follows Go formatting standards\n4. **Review checklist**: All files created/updated as described above\n5. **Create PR**: Include a clear description of what your segment does\n\nBe patient during the review process! 🏎\n\n[segment-go]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/src/config/segment_types.go\n[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes\n[docs]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/website/docs/segments\n[sidebars]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/website/sidebars.js\n[nf-icons]: https://www.nerdfonts.com/cheat-sheet\n[tests]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/src/segments/az_test.go\n[tables]: https://blog.alexellis.io/golang-writing-unit-tests/\n"
  },
  {
    "path": "website/docs/contributing/started.mdx",
    "content": "---\nid: started\ntitle: Get Started\nsidebar_label: Get Started\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\n## Get the source code\n\nThe source is hosted on [GitHub][omp]. When you want to contribute, create a [fork][gh-fork] so you can make changes in\nyour repository and create a pull request in the official Oh My Posh repository.\n\nTo clone your fork of Oh My Posh locally, open the terminal and replace `<user>` with your GitHub username.\n\n```powershell\ngit clone git@github.com:<user>/oh-my-posh.git\n```\n\n## Install dependencies\n\n<Tabs\n  defaultValue=\"manual\"\n  groupId=\"git\"\n  values={[\n    { label: 'Manual', value: 'manual', },\n    { label: 'Winget', value: 'winget', },\n  ]\n}>\n<TabItem value=\"manual\">\n\n### go\n\nThe codebase is in [go][go], meaning we need a working go setup before we can do anything else.\nHave a look at the [go guide][go-started] to get up and running with go in no time!\n\n:::caution\nOh My Posh needs at least go 1.26.0\n:::\n\n### golangci-lint\n\nTo make sure we keep on writing quality code, [golang-ci lint][golang-ci-lint] is used to validate the changes.\nHave a look at the [local installation guide][golang-ci-lint-local] to make sure you can validate this yourself as well.\n\n### nodejs\n\nThe documentation is written in markdown and uses [Docusaurus][docusaurus] to generate the website. To validate your\nchanges, you'll need to have [nodejs] installed so you can run the website locally.\n\n### Visual Studio Code\n\nIf you're not using Visual Studio Code yet, it's a great editor to work with go and the project has the configuration built-in.\nYou can download it [here][code].\n</TabItem>\n<TabItem value=\"winget\">\n\nThe project has a [winget] [configuration][winget-configuration] file available to install the dependencies.\nNavigate to the cloned repository and use winget to install the dependencies:\n\n```powershell\nwinget configure .config/configuration.winget\n```\n\nDone! Restart the terminal and you're ready to continue below.\n\n</TabItem>\n</Tabs>\n\n## Install agents and skills\n\nThis project uses [APM (Agent Package Manager)][apm] to manage shared AI agent skills.\nAfter cloning the repository, install APM and run `apm install` to pull in the shared skills:\n\n```powershell\n# Install APM\npip install apm-cli\n\n# Install shared skills\napm install\n```\n\nThis pulls in shared coding conventions (Go, PowerShell, Markdown, and conventional commits)\nfrom the [agentic][agentic] repository. Project-specific skills (segment-create and segment-docs)\nare already included in the repository under `.github/skills/`.\n\n## Configure Visual Studio Code\n\nA default config (.vscode folder) for [Visual Studio Code][code] is available in the repo:\n\n- `golangci-lint` is configured as the default linter.\n- recommended extensions available for a smooth bootstrap.\n- default run and debug configurations available.\n\nOnce the extensions are installed:\n\n- debug can be started by hitting F5.\n- all tests can be run using the Test explorer.\n\n## Running tests\n\nThe go source code can be found in the `src/` directory, make sure to navigate to that one before continuing.\n\n### Unit tests\n\n```powershell\ngo test -v ./...\n```\n\n### golangci-lint\n\n```powershell\ngolangci-lint run\n```\n\n## Building the app\n\nThe easiest way to validate your changes is to write tests. Unfortunately, as it's a visual tool, you'll want to validate\nthe changes by running the prompt in your shell as well.\n\nIf you already have Oh My Posh in your `PATH`, you'll need to either use that one as an output parameter, or make sure\nthat the `$GOPATH/bin/` folder precedes the Oh My Posh binary in your `PATH`.\n\n```powershell\ngo build -o (Get-Command oh-my-posh.exe).Source\n```\n\nAlternatively:\n\n```powershell\n$env:PATH = \"$env:GOPATH\\bin;$env:PATH\"\ngo build -o $GOPATH/bin/oh-my-posh\n```\n\n## Run the website locally\n\nOpen your terminal and navigate to the `website` folder in the repository. Install the dependencies and start the website:\n\n```powershell\nnpm install\nnpm start\n```\n\nThis will start a local server on `http://localhost:3000` where you can see your changes.\n\n## Extra tips\n\n### Configure Delve in VS Code\n\n[Delve][delve] config is restrictive by default(string limit especially). You can expand some limits in VS Code(`settings.json` or directly in `launch.json`):\n```\n\"go.delveConfig\": {\n\n  \"dlvLoadConfig\": {\n    \"followPointers\": true,\n    \"maxVariableRecurse\": 3,\n    \"maxStringLen\": 400,\n    \"maxArrayValues\": 400,\n    \"maxStructFields\": -1\n  },\n  \"apiVersion\": 2,\n  \"showGlobalVariables\": false\n}\n```\n\n## Up Next\n\nWith everything set up, you're ready to start making changes and create your first [PR][gh-pr]!\n\n[go]: https://go.dev/\n[go-started]: https://go.dev/doc/\n[golang-ci-lint]: https://golangci-lint.run\n[golang-ci-lint-local]: https://golangci-lint.run/welcome/install/#local-installation\n[gh-pr]: https://github.com/JanDeDobbeleer/oh-my-posh/pulls\n[omp]: https://github.com/JanDeDobbeleer/oh-my-posh\n[gh-fork]: https://guides.github.com/activities/forking/\n[code]: https://code.visualstudio.com\n[delve]: https://github.com/go-delve/delve\n[docusaurus]: https://docusaurus.io\n[winget-configuration]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/.config/configuration.winget\n[winget]: https://learn.microsoft.com/en-us/windows/package-manager/winget/\n[nodejs]: https://nodejs.org/en/download/\n[apm]: https://github.com/microsoft/apm\n[agentic]: https://github.com/JanDeDobbeleer/agentic\n"
  },
  {
    "path": "website/docs/contributors.md",
    "content": "---\nid: contributors\ntitle: Contributors\nsidebar_label: 🙏 Contributors\n---\n\nThanks goes to these wonderful people ([emoji key][acek]):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tbody>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lnu\"><img src=\"https://avatars.githubusercontent.com/u/1829553?v=4?s=100\" width=\"100px;\" alt=\"Laurent Nullens\"/><br /><sub><b>Laurent Nullens</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lnu\" title=\"Code\">💻</a> <a href=\"#design-lnu\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lnu\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TravisTX\"><img src=\"https://avatars.githubusercontent.com/u/934490?v=4?s=100\" width=\"100px;\" alt=\"Travis Collins\"/><br /><sub><b>Travis Collins</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TravisTX\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jos3s\"><img src=\"https://avatars.githubusercontent.com/u/50359547?v=4?s=100\" width=\"100px;\" alt=\"José Ulisses\"/><br /><sub><b>José Ulisses</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jos3s\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nwykes\"><img src=\"https://avatars.githubusercontent.com/u/593993?v=4?s=100\" width=\"100px;\" alt=\"Nathan Wykes\"/><br /><sub><b>Nathan Wykes</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=nwykes\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.paraesthesia.com/\"><img src=\"https://avatars.githubusercontent.com/u/1156571?v=4?s=100\" width=\"100px;\" alt=\"Travis Illig\"/><br /><sub><b>Travis Illig</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=tillig\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.evilznet.com/\"><img src=\"https://avatars.githubusercontent.com/u/2937862?v=4?s=100\" width=\"100px;\" alt=\"Vincent B.\"/><br /><sub><b>Vincent B.</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=evilz\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://erclu.github.io/cv/\"><img src=\"https://avatars.githubusercontent.com/u/30255227?v=4?s=100\" width=\"100px;\" alt=\"Luca Ercole\"/><br /><sub><b>Luca Ercole</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=erclu\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://larsbauer.xyz/\"><img src=\"https://avatars.githubusercontent.com/u/3920045?v=4?s=100\" width=\"100px;\" alt=\"Lars Bauer\"/><br /><sub><b>Lars Bauer</b></sub></a><br /><a href=\"#design-LarsBauer\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/RobCannon\"><img src=\"https://avatars.githubusercontent.com/u/189862?v=4?s=100\" width=\"100px;\" alt=\"Rob Cannon\"/><br /><sub><b>Rob Cannon</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=RobCannon\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Vixb1122\"><img src=\"https://avatars.githubusercontent.com/u/17810492?v=4?s=100\" width=\"100px;\" alt=\"Vixb\"/><br /><sub><b>Vixb</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Vixb1122\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/zeyugao\"><img src=\"https://avatars.githubusercontent.com/u/6374697?v=4?s=100\" width=\"100px;\" alt=\"Elsa Granger\"/><br /><sub><b>Elsa Granger</b></sub></a><br /><a href=\"#design-zeyugao\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/softweaprograma\"><img src=\"https://avatars.githubusercontent.com/u/35231092?v=4?s=100\" width=\"100px;\" alt=\"Anthony G\"/><br /><sub><b>Anthony G</b></sub></a><br /><a href=\"#design-softweaprograma\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gitolicious\"><img src=\"https://avatars.githubusercontent.com/u/26963495?v=4?s=100\" width=\"100px;\" alt=\"gitolicious\"/><br /><sub><b>gitolicious</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gitolicious\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://alzhanov.ru/\"><img src=\"https://avatars.githubusercontent.com/u/8657078?v=4?s=100\" width=\"100px;\" alt=\"Maxim\"/><br /><sub><b>Maxim</b></sub></a><br /><a href=\"#design-irdkwmnsb\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/PIYUSH194\"><img src=\"https://avatars.githubusercontent.com/u/2896456?v=4?s=100\" width=\"100px;\" alt=\"PIYUSH194\"/><br /><sub><b>PIYUSH194</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=PIYUSH194\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/97krihop\"><img src=\"https://avatars.githubusercontent.com/u/24739853?v=4?s=100\" width=\"100px;\" alt=\"97krihop\"/><br /><sub><b>97krihop</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=97krihop\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/stefanes\"><img src=\"https://avatars.githubusercontent.com/u/5484354?v=4?s=100\" width=\"100px;\" alt=\"Stefan\"/><br /><sub><b>Stefan</b></sub></a><br /><a href=\"#design-stefanes\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=stefanes\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/moritz-meier\"><img src=\"https://avatars.githubusercontent.com/u/60762067?v=4?s=100\" width=\"100px;\" alt=\"Moritz Meier\"/><br /><sub><b>Moritz Meier</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=moritz-meier\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jetersen\"><img src=\"https://avatars.githubusercontent.com/u/1661688?v=4?s=100\" width=\"100px;\" alt=\"Joseph Petersen\"/><br /><sub><b>Joseph Petersen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jetersen\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Goliaita\"><img src=\"https://avatars.githubusercontent.com/u/11245411?v=4?s=100\" width=\"100px;\" alt=\"Davide Basile\"/><br /><sub><b>Davide Basile</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Goliaita\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://youngbin.xyz/\"><img src=\"https://avatars.githubusercontent.com/u/1916739?v=4?s=100\" width=\"100px;\" alt=\"Youngbin Han\"/><br /><sub><b>Youngbin Han</b></sub></a><br /><a href=\"#design-sukso96100\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://mateusnssp.github.io/mateusnssp/\"><img src=\"https://avatars.githubusercontent.com/u/69170710?v=4?s=100\" width=\"100px;\" alt=\"Mateus Nunes\"/><br /><sub><b>Mateus Nunes</b></sub></a><br /><a href=\"#design-mateusnssn\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://pixelrobots.co.uk/\"><img src=\"https://avatars.githubusercontent.com/u/22979170?v=4?s=100\" width=\"100px;\" alt=\"PixelRobots\"/><br /><sub><b>PixelRobots</b></sub></a><br /><a href=\"#design-PixelRobots\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/RishabhSood\"><img src=\"https://avatars.githubusercontent.com/u/55499929?v=4?s=100\" width=\"100px;\" alt=\"RishabhSood\"/><br /><sub><b>RishabhSood</b></sub></a><br /><a href=\"#design-RishabhSood\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SagarYadav17\"><img src=\"https://avatars.githubusercontent.com/u/47110215?v=4?s=100\" width=\"100px;\" alt=\"Sagar Yadav\"/><br /><sub><b>Sagar Yadav</b></sub></a><br /><a href=\"#design-SagarYadav17\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/WolfspiritM\"><img src=\"https://avatars.githubusercontent.com/u/5904171?v=4?s=100\" width=\"100px;\" alt=\"Adrian\"/><br /><sub><b>Adrian</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=WolfspiritM\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MJECloud\"><img src=\"https://avatars.githubusercontent.com/u/22131101?v=4?s=100\" width=\"100px;\" alt=\"Maurice\"/><br /><sub><b>Maurice</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MJECloud\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/samuelfahrngruber\"><img src=\"https://avatars.githubusercontent.com/u/35682879?v=4?s=100\" width=\"100px;\" alt=\"samuelfahrngruber\"/><br /><sub><b>samuelfahrngruber</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=samuelfahrngruber\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/zilmarr\"><img src=\"https://avatars.githubusercontent.com/u/5557367?v=4?s=100\" width=\"100px;\" alt=\"Zilmar de Souza Junior\"/><br /><sub><b>Zilmar de Souza Junior</b></sub></a><br /><a href=\"#design-zilmarr\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AsafMah\"><img src=\"https://avatars.githubusercontent.com/u/6424271?v=4?s=100\" width=\"100px;\" alt=\"AsafMah\"/><br /><sub><b>AsafMah</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AsafMah\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cinnamon-msft\"><img src=\"https://avatars.githubusercontent.com/u/48369326?v=4?s=100\" width=\"100px;\" alt=\"Kayla Cinnamon\"/><br /><sub><b>Kayla Cinnamon</b></sub></a><br /><a href=\"#design-cinnamon-msft\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cinnamon-msft\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cinnamon-msft\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cbargren\"><img src=\"https://avatars.githubusercontent.com/u/1050712?v=4?s=100\" width=\"100px;\" alt=\"Chris Bargren\"/><br /><sub><b>Chris Bargren</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cbargren\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://tonybaloney.github.io/\"><img src=\"https://avatars.githubusercontent.com/u/1532417?v=4?s=100\" width=\"100px;\" alt=\"Anthony Shaw\"/><br /><sub><b>Anthony Shaw</b></sub></a><br /><a href=\"#design-tonybaloney\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mifieldxu\"><img src=\"https://avatars.githubusercontent.com/u/5520179?v=4?s=100\" width=\"100px;\" alt=\"Mifield\"/><br /><sub><b>Mifield</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mifieldxu\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/benallred\"><img src=\"https://avatars.githubusercontent.com/u/3902274?v=4?s=100\" width=\"100px;\" alt=\"Ben Allred\"/><br /><sub><b>Ben Allred</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=benallred\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://riazxrazor.herokuapp.com/\"><img src=\"https://avatars.githubusercontent.com/u/13194363?v=4?s=100\" width=\"100px;\" alt=\"Riaz Laskar\"/><br /><sub><b>Riaz Laskar</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=riazXrazor\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Don-Vito\"><img src=\"https://avatars.githubusercontent.com/u/4639110?v=4?s=100\" width=\"100px;\" alt=\"Don-Vito\"/><br /><sub><b>Don-Vito</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Don-Vito\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/FabianEscarate\"><img src=\"https://avatars.githubusercontent.com/u/19978896?v=4?s=100\" width=\"100px;\" alt=\"Fabian Roberto Escarate\"/><br /><sub><b>Fabian Roberto Escarate</b></sub></a><br /><a href=\"#design-FabianEscarate\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/xt0rted\"><img src=\"https://avatars.githubusercontent.com/u/831974?v=4?s=100\" width=\"100px;\" alt=\"Brian Surowiec\"/><br /><sub><b>Brian Surowiec</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=xt0rted\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://twitter.com/OJullien\"><img src=\"https://avatars.githubusercontent.com/u/3778194?v=4?s=100\" width=\"100px;\" alt=\"Olivier Jullien\"/><br /><sub><b>Olivier Jullien</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ojullien\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cdonnellytx\"><img src=\"https://avatars.githubusercontent.com/u/183046?v=4?s=100\" width=\"100px;\" alt=\"Chris Donnelly\"/><br /><sub><b>Chris Donnelly</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cdonnellytx\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/KyleCrowley\"><img src=\"https://avatars.githubusercontent.com/u/6757487?v=4?s=100\" width=\"100px;\" alt=\"Kyle Crowley\"/><br /><sub><b>Kyle Crowley</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=KyleCrowley\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gitolicious\"><img src=\"https://avatars.githubusercontent.com/u/26963495?v=4?s=100\" width=\"100px;\" alt=\"gitolicious\"/><br /><sub><b>gitolicious</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gitolicious\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jeroen7s\"><img src=\"https://avatars.githubusercontent.com/u/10954827?v=4?s=100\" width=\"100px;\" alt=\"Jeroen Evens\"/><br /><sub><b>Jeroen Evens</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jeroen7s\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/equinox\"><img src=\"https://avatars.githubusercontent.com/u/6139999?v=4?s=100\" width=\"100px;\" alt=\"equinox\"/><br /><sub><b>equinox</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=equinox\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DamianoPellegrini\"><img src=\"https://avatars.githubusercontent.com/u/41305552?v=4?s=100\" width=\"100px;\" alt=\"Damiano Pellegrini\"/><br /><sub><b>Damiano Pellegrini</b></sub></a><br /><a href=\"#design-DamianoPellegrini\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://timokrates.de/\"><img src=\"https://avatars.githubusercontent.com/u/36821505?v=4?s=100\" width=\"100px;\" alt=\"Timon Schelling\"/><br /><sub><b>Timon Schelling</b></sub></a><br /><a href=\"#design-timon-schelling\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/zeyugao\"><img src=\"https://avatars.githubusercontent.com/u/6374697?v=4?s=100\" width=\"100px;\" alt=\"Elsa Granger\"/><br /><sub><b>Elsa Granger</b></sub></a><br /><a href=\"#design-zeyugao\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://daksh.eu.org/\"><img src=\"https://avatars.githubusercontent.com/u/43648146?v=4?s=100\" width=\"100px;\" alt=\"Daksh P. Jain\"/><br /><sub><b>Daksh P. Jain</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Daksh777\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://bit-shift.com/\"><img src=\"https://avatars.githubusercontent.com/u/19351?v=4?s=100\" width=\"100px;\" alt=\"Willie Zutz\"/><br /><sub><b>Willie Zutz</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=boarder2\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/uruz-7\"><img src=\"https://avatars.githubusercontent.com/u/15071454?v=4?s=100\" width=\"100px;\" alt=\"uruz-7\"/><br /><sub><b>uruz-7</b></sub></a><br /><a href=\"#design-uruz-7\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/beppler\"><img src=\"https://avatars.githubusercontent.com/u/66092?v=4?s=100\" width=\"100px;\" alt=\"Carlos Alberto Costa Beppler\"/><br /><sub><b>Carlos Alberto Costa Beppler</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=beppler\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sky96111\"><img src=\"https://avatars.githubusercontent.com/u/22412214?v=4?s=100\" width=\"100px;\" alt=\"sky96111\"/><br /><sub><b>sky96111</b></sub></a><br /><a href=\"#design-sky96111\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://j.tlns.be/\"><img src=\"https://avatars.githubusercontent.com/u/9884103?v=4?s=100\" width=\"100px;\" alt=\"Jan Tielens\"/><br /><sub><b>Jan Tielens</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jantielens\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shedric1\"><img src=\"https://avatars.githubusercontent.com/u/56672838?v=4?s=100\" width=\"100px;\" alt=\"shedric1\"/><br /><sub><b>shedric1</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=shedric1\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sectorogo\"><img src=\"https://avatars.githubusercontent.com/u/32959212?v=4?s=100\" width=\"100px;\" alt=\"sectorogo\"/><br /><sub><b>sectorogo</b></sub></a><br /><a href=\"#design-sectorogo\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/phil-scott-78\"><img src=\"https://avatars.githubusercontent.com/u/2447331?v=4?s=100\" width=\"100px;\" alt=\"Phil Scott\"/><br /><sub><b>Phil Scott</b></sub></a><br /><a href=\"#design-phil-scott-78\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://suuu.us/\"><img src=\"https://avatars.githubusercontent.com/u/40822355?v=4?s=100\" width=\"100px;\" alt=\"Suus\"/><br /><sub><b>Suus</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=suuus\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://wopian.me/\"><img src=\"https://avatars.githubusercontent.com/u/3440094?v=4?s=100\" width=\"100px;\" alt=\"James Harris\"/><br /><sub><b>James Harris</b></sub></a><br /><a href=\"#design-wopian\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mdlopresti\"><img src=\"https://avatars.githubusercontent.com/u/1293090?v=4?s=100\" width=\"100px;\" alt=\"Michael LoPresti\"/><br /><sub><b>Michael LoPresti</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mdlopresti\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/floh96\"><img src=\"https://avatars.githubusercontent.com/u/49693964?v=4?s=100\" width=\"100px;\" alt=\"Florian Heberl\"/><br /><sub><b>Florian Heberl</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=floh96\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://tobiashoelzer.dynu.net\"><img src=\"https://avatars.githubusercontent.com/u/37540371?v=4?s=100\" width=\"100px;\" alt=\"Tobias Hölzer\"/><br /><sub><b>Tobias Hölzer</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=relativityhd\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=relativityhd\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://h4iku.github.io\"><img src=\"https://avatars.githubusercontent.com/u/3812788?v=4?s=100\" width=\"100px;\" alt=\"Reza Gharibi\"/><br /><sub><b>Reza Gharibi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=h4iku\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://justingrote.github.io\"><img src=\"https://avatars.githubusercontent.com/u/15258962?v=4?s=100\" width=\"100px;\" alt=\"Justin Grote\"/><br /><sub><b>Justin Grote</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=JustinGrote\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/henry-js\"><img src=\"https://avatars.githubusercontent.com/u/79054685?v=4?s=100\" width=\"100px;\" alt=\"James\"/><br /><sub><b>James</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=henry-js\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://wittig.dev\"><img src=\"https://avatars.githubusercontent.com/u/1031515?v=4?s=100\" width=\"100px;\" alt=\"Timothy Wittig\"/><br /><sub><b>Timothy Wittig</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=iarejenius\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Descalon\"><img src=\"https://avatars.githubusercontent.com/u/1098500?v=4?s=100\" width=\"100px;\" alt=\"Nico Glas\"/><br /><sub><b>Nico Glas</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Descalon\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hanskokx\"><img src=\"https://avatars.githubusercontent.com/u/1911919?v=4?s=100\" width=\"100px;\" alt=\"Hans Kokx\"/><br /><sub><b>Hans Kokx</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=hanskokx\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://alchatti.com\"><img src=\"https://avatars.githubusercontent.com/u/9209306?v=4?s=100\" width=\"100px;\" alt=\"Majed Al-Chatti\"/><br /><sub><b>Majed Al-Chatti</b></sub></a><br /><a href=\"#design-alchatti\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jan0660.dev\"><img src=\"https://avatars.githubusercontent.com/u/58996212?v=4?s=100\" width=\"100px;\" alt=\"Jan0660\"/><br /><sub><b>Jan0660</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Jan0660\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.m365princess.com\"><img src=\"https://avatars.githubusercontent.com/u/49960482?v=4?s=100\" width=\"100px;\" alt=\"Luise Freese\"/><br /><sub><b>Luise Freese</b></sub></a><br /><a href=\"#design-LuiseFreese\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/asherber\"><img src=\"https://avatars.githubusercontent.com/u/5248041?v=4?s=100\" width=\"100px;\" alt=\"Aaron Sherber\"/><br /><sub><b>Aaron Sherber</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=asherber\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://SeanKilleen.com\"><img src=\"https://avatars.githubusercontent.com/u/2148318?v=4?s=100\" width=\"100px;\" alt=\"Sean Killeen\"/><br /><sub><b>Sean Killeen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=SeanKilleen\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://nickcraver.com\"><img src=\"https://avatars.githubusercontent.com/u/454813?v=4?s=100\" width=\"100px;\" alt=\"Nick Craver\"/><br /><sub><b>Nick Craver</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=NickCraver\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/justin-vogt\"><img src=\"https://avatars.githubusercontent.com/u/84424169?v=4?s=100\" width=\"100px;\" alt=\"Justin Vogt\"/><br /><sub><b>Justin Vogt</b></sub></a><br /><a href=\"#design-justin-vogt\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://theonlytails.com\"><img src=\"https://avatars.githubusercontent.com/u/65342367?v=4?s=100\" width=\"100px;\" alt=\"TheOnlyTails\"/><br /><sub><b>TheOnlyTails</b></sub></a><br /><a href=\"#ideas-TheOnlyTails\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/bewing\"><img src=\"https://avatars.githubusercontent.com/u/4759896?v=4?s=100\" width=\"100px;\" alt=\"bewing\"/><br /><sub><b>bewing</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=bewing\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://wildermuth.com\"><img src=\"https://avatars.githubusercontent.com/u/568272?v=4?s=100\" width=\"100px;\" alt=\"Shawn Wildermuth\"/><br /><sub><b>Shawn Wildermuth</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=shawnwildermuth\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=shawnwildermuth\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/onpikono\"><img src=\"https://avatars.githubusercontent.com/u/25362465?v=4?s=100\" width=\"100px;\" alt=\"Ondrej Pinka\"/><br /><sub><b>Ondrej Pinka</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=onpikono\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.emanuelebartolesi.com\"><img src=\"https://avatars.githubusercontent.com/u/2757486?v=4?s=100\" width=\"100px;\" alt=\"Emanuele Bartolesi\"/><br /><sub><b>Emanuele Bartolesi</b></sub></a><br /><a href=\"#design-kasuken\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://qiansen1386.github.io\"><img src=\"https://avatars.githubusercontent.com/u/1759658?v=4?s=100\" width=\"100px;\" alt=\"Paris Qian\"/><br /><sub><b>Paris Qian</b></sub></a><br /><a href=\"#design-qiansen1386\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.itadams.co.uk\"><img src=\"https://avatars.githubusercontent.com/u/2307314?v=4?s=100\" width=\"100px;\" alt=\"Thomas Adams\"/><br /><sub><b>Thomas Adams</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=tjackadams\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.terrasoft.gr/\"><img src=\"https://avatars.githubusercontent.com/u/598065?v=4?s=100\" width=\"100px;\" alt=\"George Schizas\"/><br /><sub><b>George Schizas</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gschizas\" title=\"Code\">💻</a> <a href=\"#design-gschizas\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/denelon\"><img src=\"https://avatars.githubusercontent.com/u/61799811?v=4?s=100\" width=\"100px;\" alt=\"denelon\"/><br /><sub><b>denelon</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=denelon\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AbdelrahmanHafez\"><img src=\"https://avatars.githubusercontent.com/u/19984935?v=4?s=100\" width=\"100px;\" alt=\"Hafez\"/><br /><sub><b>Hafez</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AbdelrahmanHafez\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TedCrocker\"><img src=\"https://avatars.githubusercontent.com/u/382001?v=4?s=100\" width=\"100px;\" alt=\"Ted Ballou\"/><br /><sub><b>Ted Ballou</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TedCrocker\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TedCrocker\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://discardchanges.com\"><img src=\"https://avatars.githubusercontent.com/u/811177?v=4?s=100\" width=\"100px;\" alt=\"Mike Sigsworth\"/><br /><sub><b>Mike Sigsworth</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mikesigs\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mikesigs\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/memcpy-rand-rand-rand\"><img src=\"https://avatars.githubusercontent.com/u/90210865?v=4?s=100\" width=\"100px;\" alt=\"Will\"/><br /><sub><b>Will</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=memcpy-rand-rand-rand\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=memcpy-rand-rand-rand\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.hanselman.com\"><img src=\"https://avatars.githubusercontent.com/u/2892?v=4?s=100\" width=\"100px;\" alt=\"Scott Hanselman\"/><br /><sub><b>Scott Hanselman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=shanselman\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=shanselman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hgreving\"><img src=\"https://avatars.githubusercontent.com/u/23560667?v=4?s=100\" width=\"100px;\" alt=\"Harmjan Greving\"/><br /><sub><b>Harmjan Greving</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=hgreving\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Khaos66\"><img src=\"https://avatars.githubusercontent.com/u/4013009?v=4?s=100\" width=\"100px;\" alt=\"Khaos\"/><br /><sub><b>Khaos</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Khaos66\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Khaos66\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://mattwojo.github.io/\"><img src=\"https://avatars.githubusercontent.com/u/7566797?v=4?s=100\" width=\"100px;\" alt=\"Matt Wojciakowski\"/><br /><sub><b>Matt Wojciakowski</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mattwojo\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.powershellgallery.com/profiles/TaylorLee\"><img src=\"https://avatars.githubusercontent.com/u/53202926?v=4?s=100\" width=\"100px;\" alt=\"TheTaylorLee\"/><br /><sub><b>TheTaylorLee</b></sub></a><br /><a href=\"#design-TheTaylorLee\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/PapiPeppers\"><img src=\"https://avatars.githubusercontent.com/u/57047860?v=4?s=100\" width=\"100px;\" alt=\"Papi Peppers\"/><br /><sub><b>Papi Peppers</b></sub></a><br /><a href=\"#design-PapiPeppers\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://erresen.github.io\"><img src=\"https://avatars.githubusercontent.com/u/5566441?v=4?s=100\" width=\"100px;\" alt=\"erresen\"/><br /><sub><b>erresen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=erresen\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://aniketteredesai.com\"><img src=\"https://avatars.githubusercontent.com/u/50461557?v=4?s=100\" width=\"100px;\" alt=\"Aniket Teredesai\"/><br /><sub><b>Aniket Teredesai</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=icy-comet\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://debruyn.dev\"><img src=\"https://avatars.githubusercontent.com/u/963413?v=4?s=100\" width=\"100px;\" alt=\"Sam Debruyn\"/><br /><sub><b>Sam Debruyn</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sdebruyn\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/larserikfinholt\"><img src=\"https://avatars.githubusercontent.com/u/1328417?v=4?s=100\" width=\"100px;\" alt=\"Lars Erik Finholt\"/><br /><sub><b>Lars Erik Finholt</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=larserikfinholt\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/simorgh1\"><img src=\"https://avatars.githubusercontent.com/u/5792905?v=4?s=100\" width=\"100px;\" alt=\"Bahram Maravandi\"/><br /><sub><b>Bahram Maravandi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=simorgh1\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://developingux.com\"><img src=\"https://avatars.githubusercontent.com/u/211001?v=4?s=100\" width=\"100px;\" alt=\"Caleb Jenkins\"/><br /><sub><b>Caleb Jenkins</b></sub></a><br /><a href=\"#ideas-calebjenkins\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/FlavienMacquignon\"><img src=\"https://avatars.githubusercontent.com/u/70152975?v=4?s=100\" width=\"100px;\" alt=\"FlavienMacquignon\"/><br /><sub><b>FlavienMacquignon</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=FlavienMacquignon\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Victoria-DR\"><img src=\"https://avatars.githubusercontent.com/u/68347113?v=4?s=100\" width=\"100px;\" alt=\"Victoria\"/><br /><sub><b>Victoria</b></sub></a><br /><a href=\"#design-Victoria-DR\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/UlanaXY\"><img src=\"https://avatars.githubusercontent.com/u/12629308?v=4?s=100\" width=\"100px;\" alt=\"Mikolaj\"/><br /><sub><b>Mikolaj</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=UlanaXY\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/markbullplus\"><img src=\"https://avatars.githubusercontent.com/u/88931495?v=4?s=100\" width=\"100px;\" alt=\"markbull\"/><br /><sub><b>markbull</b></sub></a><br /><a href=\"#design-markbullplus\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/brian6932\"><img src=\"https://avatars.githubusercontent.com/u/18603393?v=4?s=100\" width=\"100px;\" alt=\"Brian\"/><br /><sub><b>Brian</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=brian6932\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.patrickhyatt.com\"><img src=\"https://avatars.githubusercontent.com/u/296125?v=4?s=100\" width=\"100px;\" alt=\"Patrick Hyatt\"/><br /><sub><b>Patrick Hyatt</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=patHyatt\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hezhizhen\"><img src=\"https://avatars.githubusercontent.com/u/7611700?v=4?s=100\" width=\"100px;\" alt=\"Zhizhen He\"/><br /><sub><b>Zhizhen He</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=hezhizhen\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jedwillick\"><img src=\"https://avatars.githubusercontent.com/u/85419773?v=4?s=100\" width=\"100px;\" alt=\"Jed Willick\"/><br /><sub><b>Jed Willick</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jedwillick\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bandism.net/\"><img src=\"https://avatars.githubusercontent.com/u/22633385?v=4?s=100\" width=\"100px;\" alt=\"Ikko Ashimine\"/><br /><sub><b>Ikko Ashimine</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=eltociear\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://prokopto.dev/\"><img src=\"https://avatars.githubusercontent.com/u/32304933?v=4?s=100\" width=\"100px;\" alt=\"Courtney Caldwell\"/><br /><sub><b>Courtney Caldwell</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=CapularisPerpetua\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rfverbruggen\"><img src=\"https://avatars.githubusercontent.com/u/2320197?v=4?s=100\" width=\"100px;\" alt=\"Robbert Verbruggen\"/><br /><sub><b>Robbert Verbruggen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rfverbruggen\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Merlin2001\"><img src=\"https://avatars.githubusercontent.com/u/13134791?v=4?s=100\" width=\"100px;\" alt=\"Marcus Mangelsdorf\"/><br /><sub><b>Marcus Mangelsdorf</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Merlin2001\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/andresrinivasan\"><img src=\"https://avatars.githubusercontent.com/u/134301?v=4?s=100\" width=\"100px;\" alt=\"André Srinivasan\"/><br /><sub><b>André Srinivasan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=andresrinivasan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ehawman-rosenberg\"><img src=\"https://avatars.githubusercontent.com/u/81652082?v=4?s=100\" width=\"100px;\" alt=\"ehawman-rosenberg\"/><br /><sub><b>ehawman-rosenberg</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ehawman-rosenberg\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ehawman-rosenberg\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://spizzi.net/\"><img src=\"https://avatars.githubusercontent.com/u/1934246?v=4?s=100\" width=\"100px;\" alt=\"Claudio Spizzi\"/><br /><sub><b>Claudio Spizzi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=claudiospizzi\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.eliostruyf.com\"><img src=\"https://avatars.githubusercontent.com/u/2900833?v=4?s=100\" width=\"100px;\" alt=\"Elio Struyf\"/><br /><sub><b>Elio Struyf</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=estruyf\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=estruyf\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.olafalders.com/\"><img src=\"https://avatars.githubusercontent.com/u/96205?v=4?s=100\" width=\"100px;\" alt=\"Olaf Alders\"/><br /><sub><b>Olaf Alders</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=oalders\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.deltacode.be\"><img src=\"https://avatars.githubusercontent.com/u/352626?v=4?s=100\" width=\"100px;\" alt=\"David De Sloovere\"/><br /><sub><b>David De Sloovere</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=DavidDeSloovere\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lensor-radii.netlify.app\"><img src=\"https://avatars.githubusercontent.com/u/69637718?v=4?s=100\" width=\"100px;\" alt=\"LensPlaysGames\"/><br /><sub><b>LensPlaysGames</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=LensPlaysGames\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://takiya.eu\"><img src=\"https://avatars.githubusercontent.com/u/6952402?v=4?s=100\" width=\"100px;\" alt=\"Alex 'Avunia' Takiya\"/><br /><sub><b>Alex 'Avunia' Takiya</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=atakiya\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kenmorse\"><img src=\"https://avatars.githubusercontent.com/u/63734484?v=4?s=100\" width=\"100px;\" alt=\"kenmorse\"/><br /><sub><b>kenmorse</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kenmorse\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/xadozuk\"><img src=\"https://avatars.githubusercontent.com/u/780423?v=4?s=100\" width=\"100px;\" alt=\"xadozuk\"/><br /><sub><b>xadozuk</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=xadozuk\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bittu.eu.org\"><img src=\"https://avatars.githubusercontent.com/u/83997633?v=4?s=100\" width=\"100px;\" alt=\"Vedant\"/><br /><sub><b>Vedant</b></sub></a><br /><a href=\"#design-vedantmgoyal9\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=vedantmgoyal9\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lewis-yeung\"><img src=\"https://avatars.githubusercontent.com/u/83903009?v=4?s=100\" width=\"100px;\" alt=\"L. Yeung\"/><br /><sub><b>L. Yeung</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lewis-yeung\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lewis-yeung\" title=\"Documentation\">📖</a> <a href=\"#design-lewis-yeung\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antoson\"><img src=\"https://avatars.githubusercontent.com/u/36371990?v=4?s=100\" width=\"100px;\" alt=\"Ondrej Antos\"/><br /><sub><b>Ondrej Antos</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=antoson\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Bahnschrift\"><img src=\"https://avatars.githubusercontent.com/u/31170809?v=4?s=100\" width=\"100px;\" alt=\"Bahnschrift\"/><br /><sub><b>Bahnschrift</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Bahnschrift\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jakeboone02\"><img src=\"https://avatars.githubusercontent.com/u/366438?v=4?s=100\" width=\"100px;\" alt=\"Jake Boone\"/><br /><sub><b>Jake Boone</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jakeboone02\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kapsiR\"><img src=\"https://avatars.githubusercontent.com/u/7165033?v=4?s=100\" width=\"100px;\" alt=\"kapsiR\"/><br /><sub><b>kapsiR</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kapsiR\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kapsiR\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/csrakowski\"><img src=\"https://avatars.githubusercontent.com/u/1303967?v=4?s=100\" width=\"100px;\" alt=\"Christiaan Rakowski\"/><br /><sub><b>Christiaan Rakowski</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=csrakowski\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=csrakowski\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mosullivan93\"><img src=\"https://avatars.githubusercontent.com/u/7676935?v=4?s=100\" width=\"100px;\" alt=\"Mitchell J. O'Sullivan\"/><br /><sub><b>Mitchell J. O'Sullivan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mosullivan93\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mosullivan93\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/felpel\"><img src=\"https://avatars.githubusercontent.com/u/5000004?v=4?s=100\" width=\"100px;\" alt=\"Félix Pelletier\"/><br /><sub><b>Félix Pelletier</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=felpel\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://nexiom.net/\"><img src=\"https://avatars.githubusercontent.com/u/3214803?v=4?s=100\" width=\"100px;\" alt=\"Samuel D. Leslie\"/><br /><sub><b>Samuel D. Leslie</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ralish\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AjayKMehta\"><img src=\"https://avatars.githubusercontent.com/u/11180071?v=4?s=100\" width=\"100px;\" alt=\"Ajay Mehta\"/><br /><sub><b>Ajay Mehta</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AjayKMehta\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/the-eduardo\"><img src=\"https://avatars.githubusercontent.com/u/40523695?v=4?s=100\" width=\"100px;\" alt=\"the-eduardo\"/><br /><sub><b>the-eduardo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=the-eduardo\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/antonpiatek\"><img src=\"https://avatars.githubusercontent.com/u/175077?v=4?s=100\" width=\"100px;\" alt=\"Anton Piatek\"/><br /><sub><b>Anton Piatek</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=antonpiatek\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://careers.stackoverflow.com/dehghan\"><img src=\"https://avatars.githubusercontent.com/u/1384790?v=4?s=100\" width=\"100px;\" alt=\"Mohammad Dehghan\"/><br /><sub><b>Mohammad Dehghan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=prodehghan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/bhagerty\"><img src=\"https://avatars.githubusercontent.com/u/7828454?v=4?s=100\" width=\"100px;\" alt=\"bhagerty\"/><br /><sub><b>bhagerty</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=bhagerty\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/CodyScavenger\"><img src=\"https://avatars.githubusercontent.com/u/94334877?v=4?s=100\" width=\"100px;\" alt=\"Cody Scavenger\"/><br /><sub><b>Cody Scavenger</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=CodyScavenger\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://fwest98.nl/\"><img src=\"https://avatars.githubusercontent.com/u/1918658?v=4?s=100\" width=\"100px;\" alt=\"Floris Westerman\"/><br /><sub><b>Floris Westerman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=FWest98\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mjcarman\"><img src=\"https://avatars.githubusercontent.com/u/121028?v=4?s=100\" width=\"100px;\" alt=\"Michael Carman\"/><br /><sub><b>Michael Carman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mjcarman\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mjcarman\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/entr0pia\"><img src=\"https://avatars.githubusercontent.com/u/30486766?v=4?s=100\" width=\"100px;\" alt=\"风沐白\"/><br /><sub><b>风沐白</b></sub></a><br /><a href=\"#design-entr0pia\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/schallm\"><img src=\"https://avatars.githubusercontent.com/u/331167?v=4?s=100\" width=\"100px;\" alt=\"Michael T. Schall\"/><br /><sub><b>Michael T. Schall</b></sub></a><br /><a href=\"#design-schallm\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/craiglpeters\"><img src=\"https://avatars.githubusercontent.com/u/9445180?v=4?s=100\" width=\"100px;\" alt=\"Craig Peters\"/><br /><sub><b>Craig Peters</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=craiglpeters\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dorian-li\"><img src=\"https://avatars.githubusercontent.com/u/49279922?v=4?s=100\" width=\"100px;\" alt=\"Dongyu Li\"/><br /><sub><b>Dongyu Li</b></sub></a><br /><a href=\"#design-dorian-li\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/cyberbliss\"><img src=\"https://avatars.githubusercontent.com/u/5401528?v=4?s=100\" width=\"100px;\" alt=\"Stephen Judd\"/><br /><sub><b>Stephen Judd</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cyberbliss\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://douug.dev\"><img src=\"https://avatars.githubusercontent.com/u/59324692?v=4?s=100\" width=\"100px;\" alt=\"Douglas Silva\"/><br /><sub><b>Douglas Silva</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=douugdev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BoseSj\"><img src=\"https://avatars.githubusercontent.com/u/58129377?v=4?s=100\" width=\"100px;\" alt=\"SJ Basak\"/><br /><sub><b>SJ Basak</b></sub></a><br /><a href=\"#design-BoseSj\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://tedreed.info\"><img src=\"https://avatars.githubusercontent.com/u/71910?v=4?s=100\" width=\"100px;\" alt=\"Ted Reed\"/><br /><sub><b>Ted Reed</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=treed\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=treed\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://albertp.dev\"><img src=\"https://avatars.githubusercontent.com/u/14863373?v=4?s=100\" width=\"100px;\" alt=\"Albert Portnoy\"/><br /><sub><b>Albert Portnoy</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=asportnoy\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=asportnoy\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.msbrg.net/\"><img src=\"https://avatars.githubusercontent.com/u/1346676?v=4?s=100\" width=\"100px;\" alt=\"Sebastian\"/><br /><sub><b>Sebastian</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Lemorz56\" title=\"Code\">💻</a> <a href=\"#design-Lemorz56\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Lemorz56\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mirsella\"><img src=\"https://avatars.githubusercontent.com/u/45905567?v=4?s=100\" width=\"100px;\" alt=\"Lucas\"/><br /><sub><b>Lucas</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mirsella\" title=\"Code\">💻</a> <a href=\"#design-mirsella\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mirsella\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ethansocal\"><img src=\"https://avatars.githubusercontent.com/u/79533577?v=4?s=100\" width=\"100px;\" alt=\"Ethan\"/><br /><sub><b>Ethan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ethansocal\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/astronaako\"><img src=\"https://avatars.githubusercontent.com/u/18577543?v=4?s=100\" width=\"100px;\" alt=\"Mohamed Naamy\"/><br /><sub><b>Mohamed Naamy</b></sub></a><br /><a href=\"#design-astronaako\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://bend-n.github.io\"><img src=\"https://avatars.githubusercontent.com/u/70787919?v=4?s=100\" width=\"100px;\" alt=\"bendn\"/><br /><sub><b>bendn</b></sub></a><br /><a href=\"#design-bend-n\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.david-anthoff.com\"><img src=\"https://avatars.githubusercontent.com/u/1036561?v=4?s=100\" width=\"100px;\" alt=\"David Anthoff\"/><br /><sub><b>David Anthoff</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=davidanthoff\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=davidanthoff\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jooooel\"><img src=\"https://avatars.githubusercontent.com/u/9303280?v=4?s=100\" width=\"100px;\" alt=\"jooooel\"/><br /><sub><b>jooooel</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jooooel\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/maxlandon\"><img src=\"https://avatars.githubusercontent.com/u/25826036?v=4?s=100\" width=\"100px;\" alt=\"maxlandon\"/><br /><sub><b>maxlandon</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=maxlandon\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://linolevan.com\"><img src=\"https://avatars.githubusercontent.com/u/11367844?v=4?s=100\" width=\"100px;\" alt=\"Lino Le Van\"/><br /><sub><b>Lino Le Van</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lino-levan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dvlprJobayer\"><img src=\"https://avatars.githubusercontent.com/u/76583359?v=4?s=100\" width=\"100px;\" alt=\"Jobayer Ahammed Patwary\"/><br /><sub><b>Jobayer Ahammed Patwary</b></sub></a><br /><a href=\"#design-dvlprJobayer\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/NoF0rte\"><img src=\"https://avatars.githubusercontent.com/u/64100993?v=4?s=100\" width=\"100px;\" alt=\"NoF0rte\"/><br /><sub><b>NoF0rte</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=NoF0rte\" title=\"Code\">💻</a> <a href=\"#design-NoF0rte\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=NoF0rte\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/LNKLEO\"><img src=\"https://avatars.githubusercontent.com/u/10334184?v=4?s=100\" width=\"100px;\" alt=\"LNKLEO\"/><br /><sub><b>LNKLEO</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=LNKLEO\" title=\"Code\">💻</a> <a href=\"#design-LNKLEO\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=LNKLEO\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kamfaima\"><img src=\"https://avatars.githubusercontent.com/u/23546392?v=4?s=100\" width=\"100px;\" alt=\"kamfaima\"/><br /><sub><b>kamfaima</b></sub></a><br /><a href=\"#design-kamfaima\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dhrdlicka\"><img src=\"https://avatars.githubusercontent.com/u/13226155?v=4?s=100\" width=\"100px;\" alt=\"David Hrdlička\"/><br /><sub><b>David Hrdlička</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dhrdlicka\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dhrdlicka\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://davidcourtney.com\"><img src=\"https://avatars.githubusercontent.com/u/1019134?v=4?s=100\" width=\"100px;\" alt=\"David Courtney\"/><br /><sub><b>David Courtney</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=davidcourtney\" title=\"Code\">💻</a> <a href=\"#design-davidcourtney\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=davidcourtney\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Jensdevloo\"><img src=\"https://avatars.githubusercontent.com/u/2276152?v=4?s=100\" width=\"100px;\" alt=\"jensdevloo\"/><br /><sub><b>jensdevloo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Jensdevloo\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thomasdoerr\"><img src=\"https://avatars.githubusercontent.com/u/6919685?v=4?s=100\" width=\"100px;\" alt=\"Thomas Dörr\"/><br /><sub><b>Thomas Dörr</b></sub></a><br /><a href=\"#design-thomasdoerr\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.aelterman.com\"><img src=\"https://avatars.githubusercontent.com/u/17446043?v=4?s=100\" width=\"100px;\" alt=\"Sven Aelterman\"/><br /><sub><b>Sven Aelterman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=SvenAelterman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/CodexLink\"><img src=\"https://avatars.githubusercontent.com/u/5953927?v=4?s=100\" width=\"100px;\" alt=\"Janrey Licas\"/><br /><sub><b>Janrey Licas</b></sub></a><br /><a href=\"#design-CodexLink\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=CodexLink\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=CodexLink\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/padilo\"><img src=\"https://avatars.githubusercontent.com/u/783959?v=4?s=100\" width=\"100px;\" alt=\"Pablo Díaz-López\"/><br /><sub><b>Pablo Díaz-López</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=padilo\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DarkMagicSource\"><img src=\"https://avatars.githubusercontent.com/u/35950530?v=4?s=100\" width=\"100px;\" alt=\"Caitlyn Williams\"/><br /><sub><b>Caitlyn Williams</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=DarkMagicSource\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gork3n\"><img src=\"https://avatars.githubusercontent.com/u/1086155?v=4?s=100\" width=\"100px;\" alt=\"Christopher Henderson\"/><br /><sub><b>Christopher Henderson</b></sub></a><br /><a href=\"#design-gork3n\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.coltbauman.com\"><img src=\"https://avatars.githubusercontent.com/u/6819362?v=4?s=100\" width=\"100px;\" alt=\"Colt\"/><br /><sub><b>Colt</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cabauman\" title=\"Code\">💻</a> <a href=\"#design-cabauman\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=cabauman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/craftzneko\"><img src=\"https://avatars.githubusercontent.com/u/662108?v=4?s=100\" width=\"100px;\" alt=\"craftzneko\"/><br /><sub><b>craftzneko</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=craftzneko\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://waferlab.dev\"><img src=\"https://avatars.githubusercontent.com/u/17683244?v=4?s=100\" width=\"100px;\" alt=\"甘亭\"/><br /><sub><b>甘亭</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=atlanswer\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Mertsch\"><img src=\"https://avatars.githubusercontent.com/u/9402861?v=4?s=100\" width=\"100px;\" alt=\"Mertsch\"/><br /><sub><b>Mertsch</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Mertsch\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://mespin.me/\"><img src=\"https://avatars.githubusercontent.com/u/38158676?v=4?s=100\" width=\"100px;\" alt=\"Marc Espín\"/><br /><sub><b>Marc Espín</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=marc2332\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ksdpmx\"><img src=\"https://avatars.githubusercontent.com/u/3256083?v=4?s=100\" width=\"100px;\" alt=\"jasonz\"/><br /><sub><b>jasonz</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ksdpmx\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ksdpmx\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bentsukun.ch\"><img src=\"https://avatars.githubusercontent.com/u/866330?v=4?s=100\" width=\"100px;\" alt=\"Benny Siegert\"/><br /><sub><b>Benny Siegert</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=bsiegert\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.kemadev.fr/fr/\"><img src=\"https://avatars.githubusercontent.com/u/54537427?v=4?s=100\" width=\"100px;\" alt=\"kema\"/><br /><sub><b>kema</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kema-dev\" title=\"Code\">💻</a> <a href=\"#design-kema-dev\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kema-dev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://mavaddat.ca\"><img src=\"https://avatars.githubusercontent.com/u/5055400?v=4?s=100\" width=\"100px;\" alt=\"Mavaddat Javid\"/><br /><sub><b>Mavaddat Javid</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mavaddat\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://iavael.name/\"><img src=\"https://avatars.githubusercontent.com/u/905853?v=4?s=100\" width=\"100px;\" alt=\"Iavael\"/><br /><sub><b>Iavael</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=iavael\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Kushal-Chandar\"><img src=\"https://avatars.githubusercontent.com/u/83660514?v=4?s=100\" width=\"100px;\" alt=\"Kushal-Chandar\"/><br /><sub><b>Kushal-Chandar</b></sub></a><br /><a href=\"#design-Kushal-Chandar\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.project-miller.com/\"><img src=\"https://avatars.githubusercontent.com/u/2429638?v=4?s=100\" width=\"100px;\" alt=\"Matthew Miller\"/><br /><sub><b>Matthew Miller</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BigBear0812\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BigBear0812\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/javidcf\"><img src=\"https://avatars.githubusercontent.com/u/1098280?v=4?s=100\" width=\"100px;\" alt=\"Javier Dehesa\"/><br /><sub><b>Javier Dehesa</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=javidcf\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://alex-v.blog/\"><img src=\"https://avatars.githubusercontent.com/u/716334?v=4?s=100\" width=\"100px;\" alt=\"Alex Villarreal\"/><br /><sub><b>Alex Villarreal</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=alexvy86\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/krzysdz\"><img src=\"https://avatars.githubusercontent.com/u/12915102?v=4?s=100\" width=\"100px;\" alt=\"krzysdz\"/><br /><sub><b>krzysdz</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=krzysdz\" title=\"Code\">💻</a> <a href=\"#design-krzysdz\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=krzysdz\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://blog.baslijten.com\"><img src=\"https://avatars.githubusercontent.com/u/11842067?v=4?s=100\" width=\"100px;\" alt=\"Bas Lijten\"/><br /><sub><b>Bas Lijten</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BasLijten\" title=\"Code\">💻</a> <a href=\"#design-BasLijten\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BasLijten\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ParkerM\"><img src=\"https://avatars.githubusercontent.com/u/5124113?v=4?s=100\" width=\"100px;\" alt=\"Parker Mauney\"/><br /><sub><b>Parker Mauney</b></sub></a><br /><a href=\"#design-ParkerM\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.brusella.com.ar\"><img src=\"https://avatars.githubusercontent.com/u/115679?v=4?s=100\" width=\"100px;\" alt=\"Gonzalo Brusella\"/><br /><sub><b>Gonzalo Brusella</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gbrusella\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/krokofant\"><img src=\"https://avatars.githubusercontent.com/u/5908498?v=4?s=100\" width=\"100px;\" alt=\"Emil Sundin\"/><br /><sub><b>Emil Sundin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=krokofant\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://dysuby.github.io\"><img src=\"https://avatars.githubusercontent.com/u/26317510?v=4?s=100\" width=\"100px;\" alt=\"dysuby\"/><br /><sub><b>dysuby</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dysuby\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dorokhin-bohdan\"><img src=\"https://avatars.githubusercontent.com/u/24988081?v=4?s=100\" width=\"100px;\" alt=\"Bohdan Dorokhin\"/><br /><sub><b>Bohdan Dorokhin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dorokhin-bohdan\" title=\"Code\">💻</a> <a href=\"#design-dorokhin-bohdan\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dorokhin-bohdan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/CY-Pan\"><img src=\"https://avatars.githubusercontent.com/u/59761962?v=4?s=100\" width=\"100px;\" alt=\"Ad Red\"/><br /><sub><b>Ad Red</b></sub></a><br /><a href=\"#design-CY-Pan\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/nopeless\"><img src=\"https://avatars.githubusercontent.com/u/38830903?v=4?s=100\" width=\"100px;\" alt=\"nopeless\"/><br /><sub><b>nopeless</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=nopeless\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=nopeless\" title=\"Documentation\">📖</a> <a href=\"#design-nopeless\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://linkedin.com/in/vinhloc30796\"><img src=\"https://avatars.githubusercontent.com/u/19675202?v=4?s=100\" width=\"100px;\" alt=\"Loc Nguyen\"/><br /><sub><b>Loc Nguyen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=vinhloc30796\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://tavis.page\"><img src=\"https://avatars.githubusercontent.com/u/66774833?v=4?s=100\" width=\"100px;\" alt=\"Tavi\"/><br /><sub><b>Tavi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Coder-Tavi\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ndawson.me\"><img src=\"https://avatars.githubusercontent.com/u/37987430?v=4?s=100\" width=\"100px;\" alt=\"Nick Dawson\"/><br /><sub><b>Nick Dawson</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=NicholasDawson\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.jntrnr.com/\"><img src=\"https://avatars.githubusercontent.com/u/547158?v=4?s=100\" width=\"100px;\" alt=\"JT\"/><br /><sub><b>JT</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jntrnr\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ChandanChainani\"><img src=\"https://avatars.githubusercontent.com/u/28807775?v=4?s=100\" width=\"100px;\" alt=\"ChandanChainani\"/><br /><sub><b>ChandanChainani</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ChandanChainani\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jenspinney\"><img src=\"https://avatars.githubusercontent.com/u/3200507?v=4?s=100\" width=\"100px;\" alt=\"Jen Spinney\"/><br /><sub><b>Jen Spinney</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jenspinney\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jenspinney\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rotu\"><img src=\"https://avatars.githubusercontent.com/u/119948?v=4?s=100\" width=\"100px;\" alt=\"Dan Rose\"/><br /><sub><b>Dan Rose</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rotu\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://carlwa.com\"><img src=\"https://avatars.githubusercontent.com/u/2829438?v=4?s=100\" width=\"100px;\" alt=\"Carl Walsh\"/><br /><sub><b>Carl Walsh</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=darthwalsh\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ercpereda\"><img src=\"https://avatars.githubusercontent.com/u/13546685?v=4?s=100\" width=\"100px;\" alt=\"Ernesto R. C. Pereda\"/><br /><sub><b>Ernesto R. C. Pereda</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ercpereda\" title=\"Code\">💻</a> <a href=\"#design-ercpereda\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ercpereda\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0Ky\"><img src=\"https://avatars.githubusercontent.com/u/16103757?v=4?s=100\" width=\"100px;\" alt=\"ｃｒｙｐｔｉｘ\"/><br /><sub><b>ｃｒｙｐｔｉｘ</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=0Ky\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ehawman\"><img src=\"https://avatars.githubusercontent.com/u/52979227?v=4?s=100\" width=\"100px;\" alt=\"Evan Hawman\"/><br /><sub><b>Evan Hawman</b></sub></a><br /><a href=\"#design-ehawman\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://zerdox.dev\"><img src=\"https://avatars.githubusercontent.com/u/49815452?v=4?s=100\" width=\"100px;\" alt=\"Mark Lansky\"/><br /><sub><b>Mark Lansky</b></sub></a><br /><a href=\"#design-ZerdoX-x\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/pulsation\"><img src=\"https://avatars.githubusercontent.com/u/1838397?v=4?s=100\" width=\"100px;\" alt=\"pulsation\"/><br /><sub><b>pulsation</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=pulsation\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://oriondev.fr\"><img src=\"https://avatars.githubusercontent.com/u/38093786?v=4?s=100\" width=\"100px;\" alt=\"orionsource\"/><br /><sub><b>orionsource</b></sub></a><br /><a href=\"#design-oriionn\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/CesarGBkR\"><img src=\"https://avatars.githubusercontent.com/u/99093357?v=4?s=100\" width=\"100px;\" alt=\"Cesar Garduño\"/><br /><sub><b>Cesar Garduño</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=CesarGBkR\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Adi-vig\"><img src=\"https://avatars.githubusercontent.com/u/123308369?v=4?s=100\" width=\"100px;\" alt=\"Aditya Sakhare\"/><br /><sub><b>Aditya Sakhare</b></sub></a><br /><a href=\"#design-Adi-vig\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/deepak-dev-96\"><img src=\"https://avatars.githubusercontent.com/u/134447761?v=4?s=100\" width=\"100px;\" alt=\"Deepak Dev\"/><br /><sub><b>Deepak Dev</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=deepak-dev-96\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://creativewebspecialist.co.uk\"><img src=\"https://avatars.githubusercontent.com/u/1389894?v=4?s=100\" width=\"100px;\" alt=\"Warren Buckley\"/><br /><sub><b>Warren Buckley</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=warrenbuckley\" title=\"Code\">💻</a> <a href=\"#design-warrenbuckley\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=warrenbuckley\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/LunarMarathon\"><img src=\"https://avatars.githubusercontent.com/u/113847439?v=4?s=100\" width=\"100px;\" alt=\"LunarMarathon\"/><br /><sub><b>LunarMarathon</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=LunarMarathon\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ginglis.me\"><img src=\"https://avatars.githubusercontent.com/u/43075615?v=4?s=100\" width=\"100px;\" alt=\"Gavin Inglis\"/><br /><sub><b>Gavin Inglis</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ginglis13\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://jaliyaudagedara.blogspot.com\"><img src=\"https://avatars.githubusercontent.com/u/5653381?v=4?s=100\" width=\"100px;\" alt=\"Jaliya Udagedara\"/><br /><sub><b>Jaliya Udagedara</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jaliyaudagedara\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BPplays\"><img src=\"https://avatars.githubusercontent.com/u/58504799?v=4?s=100\" width=\"100px;\" alt=\"BPplays\"/><br /><sub><b>BPplays</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BPplays\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mateusz-bajorek\"><img src=\"https://avatars.githubusercontent.com/u/11185738?v=4?s=100\" width=\"100px;\" alt=\"Mateusz Bajorek\"/><br /><sub><b>Mateusz Bajorek</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mateusz-bajorek\" title=\"Code\">💻</a> <a href=\"#design-mateusz-bajorek\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mateusz-bajorek\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://joshbduncan.com\"><img src=\"https://avatars.githubusercontent.com/u/44387852?v=4?s=100\" width=\"100px;\" alt=\"Josh Duncan\"/><br /><sub><b>Josh Duncan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=joshbduncan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/princesaini\"><img src=\"https://avatars.githubusercontent.com/u/25565506?v=4?s=100\" width=\"100px;\" alt=\"Prince Saini\"/><br /><sub><b>Prince Saini</b></sub></a><br /><a href=\"#design-princesaini\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/fabriciojuliano/\"><img src=\"https://avatars.githubusercontent.com/u/70244182?v=4?s=100\" width=\"100px;\" alt=\"fabriciojlm\"/><br /><sub><b>fabriciojlm</b></sub></a><br /><a href=\"#design-fabriciojlm\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/SriRamanujam\"><img src=\"https://avatars.githubusercontent.com/u/2983875?v=4?s=100\" width=\"100px;\" alt=\"Sri Ramanujam\"/><br /><sub><b>Sri Ramanujam</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=SriRamanujam\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=SriRamanujam\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Juneezee\"><img src=\"https://avatars.githubusercontent.com/u/20135478?v=4?s=100\" width=\"100px;\" alt=\"Eng Zer Jun\"/><br /><sub><b>Eng Zer Jun</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Juneezee\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://alexpotter.dev\"><img src=\"https://avatars.githubusercontent.com/u/14200888?v=4?s=100\" width=\"100px;\" alt=\"Alex Potter\"/><br /><sub><b>Alex Potter</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AlexJPotter\" title=\"Code\">💻</a> <a href=\"#design-AlexJPotter\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AlexJPotter\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://mishmanners.info\"><img src=\"https://avatars.githubusercontent.com/u/36594527?v=4?s=100\" width=\"100px;\" alt=\"Michelle Mannering\"/><br /><sub><b>Michelle Mannering</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mishmanners\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/paulomorgado\"><img src=\"https://avatars.githubusercontent.com/u/470455?v=4?s=100\" width=\"100px;\" alt=\"Paulo Morgado\"/><br /><sub><b>Paulo Morgado</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=paulomorgado\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=paulomorgado\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/joadoumie\"><img src=\"https://avatars.githubusercontent.com/u/98557455?v=4?s=100\" width=\"100px;\" alt=\"joadoumie\"/><br /><sub><b>joadoumie</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=joadoumie\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=joadoumie\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://about.me/flanakin\"><img src=\"https://avatars.githubusercontent.com/u/399533?v=4?s=100\" width=\"100px;\" alt=\"Michael Flanakin\"/><br /><sub><b>Michael Flanakin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=flanakin\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/thiagobarros95/\"><img src=\"https://avatars.githubusercontent.com/u/88802518?v=4?s=100\" width=\"100px;\" alt=\"Thiago Barros\"/><br /><sub><b>Thiago Barros</b></sub></a><br /><a href=\"#design-thiagoszbarros\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/TendTo\"><img src=\"https://avatars.githubusercontent.com/u/65033249?v=4?s=100\" width=\"100px;\" alt=\"Tend\"/><br /><sub><b>Tend</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TendTo\" title=\"Code\">💻</a> <a href=\"#design-TendTo\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TendTo\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kibbewater.com\"><img src=\"https://avatars.githubusercontent.com/u/35224538?v=4?s=100\" width=\"100px;\" alt=\"Snow\"/><br /><sub><b>Snow</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=KibbeWater\" title=\"Code\">💻</a> <a href=\"#design-KibbeWater\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=KibbeWater\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/randombenj\"><img src=\"https://avatars.githubusercontent.com/u/5184499?v=4?s=100\" width=\"100px;\" alt=\"Benj Fassbind\"/><br /><sub><b>Benj Fassbind</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=randombenj\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://blog.liudonghua.top\"><img src=\"https://avatars.githubusercontent.com/u/2276718?v=4?s=100\" width=\"100px;\" alt=\"liudonghua\"/><br /><sub><b>liudonghua</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=liudonghua123\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://somoy.me\"><img src=\"https://avatars.githubusercontent.com/u/40368688?v=4?s=100\" width=\"100px;\" alt=\"Somoy Subandhu\"/><br /><sub><b>Somoy Subandhu</b></sub></a><br /><a href=\"#design-Somoy73\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/oleksbabieiev\"><img src=\"https://avatars.githubusercontent.com/u/64398691?v=4?s=100\" width=\"100px;\" alt=\"Oleksandr Babieiev\"/><br /><sub><b>Oleksandr Babieiev</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=oleksbabieiev\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=oleksbabieiev\" title=\"Documentation\">📖</a> <a href=\"#design-oleksbabieiev\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mrbeardad\"><img src=\"https://avatars.githubusercontent.com/u/54128430?v=4?s=100\" width=\"100px;\" alt=\"Heache Bear\"/><br /><sub><b>Heache Bear</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mrbeardad\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://ensif.com\"><img src=\"https://avatars.githubusercontent.com/u/125232146?v=4?s=100\" width=\"100px;\" alt=\"Christopher Narowski\"/><br /><sub><b>Christopher Narowski</b></sub></a><br /><a href=\"#design-ChrisNSki\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sino1641\"><img src=\"https://avatars.githubusercontent.com/u/13870295?v=4?s=100\" width=\"100px;\" alt=\"Sin\"/><br /><sub><b>Sin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sino1641\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kebo.xyz\"><img src=\"https://avatars.githubusercontent.com/u/601636?v=4?s=100\" width=\"100px;\" alt=\"Kenta Kubo\"/><br /><sub><b>Kenta Kubo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kkk669\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://mfedatto.com\"><img src=\"https://avatars.githubusercontent.com/u/5623739?v=4?s=100\" width=\"100px;\" alt=\"MFedatto\"/><br /><sub><b>MFedatto</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mfedatto\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/riikka-l-861694b2/\"><img src=\"https://avatars.githubusercontent.com/u/56921531?v=4?s=100\" width=\"100px;\" alt=\"Riikka\"/><br /><sub><b>Riikka</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=RiikkaDream\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/srpmtt\"><img src=\"https://avatars.githubusercontent.com/u/11175503?v=4?s=100\" width=\"100px;\" alt=\"srpmtt\"/><br /><sub><b>srpmtt</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=srpmtt\" title=\"Code\">💻</a> <a href=\"#design-srpmtt\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=srpmtt\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://chris-johnston.me\"><img src=\"https://avatars.githubusercontent.com/u/16418643?v=4?s=100\" width=\"100px;\" alt=\"Chris Johnston\"/><br /><sub><b>Chris Johnston</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Chris-Johnston\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Daimonion1980\"><img src=\"https://avatars.githubusercontent.com/u/12880413?v=4?s=100\" width=\"100px;\" alt=\"Thomas\"/><br /><sub><b>Thomas</b></sub></a><br /><a href=\"#design-Daimonion1980\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://veert00x.com\"><img src=\"https://avatars.githubusercontent.com/u/72668825?v=4?s=100\" width=\"100px;\" alt=\"Veko\"/><br /><sub><b>Veko</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=VEERT00X\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://lucascosti.com\"><img src=\"https://avatars.githubusercontent.com/u/4434330?v=4?s=100\" width=\"100px;\" alt=\"Lucas Costi\"/><br /><sub><b>Lucas Costi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lucascosti\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://krason.dev/\"><img src=\"https://avatars.githubusercontent.com/u/11185582?v=4?s=100\" width=\"100px;\" alt=\"Grzegorz Krasoń\"/><br /><sub><b>Grzegorz Krasoń</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gergelyk\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rockyoung\"><img src=\"https://avatars.githubusercontent.com/u/1207971?v=4?s=100\" width=\"100px;\" alt=\"rockyoung\"/><br /><sub><b>rockyoung</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rockyoung\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rockyoung\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/shravanasati\"><img src=\"https://avatars.githubusercontent.com/u/69118069?v=4?s=100\" width=\"100px;\" alt=\"Shravan Asati\"/><br /><sub><b>Shravan Asati</b></sub></a><br /><a href=\"#design-shravanasati\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lzecca78\"><img src=\"https://avatars.githubusercontent.com/u/3881844?v=4?s=100\" width=\"100px;\" alt=\"Luca Zecca\"/><br /><sub><b>Luca Zecca</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lzecca78\" title=\"Code\">💻</a> <a href=\"#design-lzecca78\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lzecca78\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jreilly-lukava\"><img src=\"https://avatars.githubusercontent.com/u/30353736?v=4?s=100\" width=\"100px;\" alt=\"Joshua Reilly\"/><br /><sub><b>Joshua Reilly</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jreilly-lukava\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jreilly-lukava\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://ivan-the-terrible.github.io/\"><img src=\"https://avatars.githubusercontent.com/u/56458442?v=4?s=100\" width=\"100px;\" alt=\"Ivan\"/><br /><sub><b>Ivan</b></sub></a><br /><a href=\"#design-ivan-the-terrible\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ivan-the-terrible\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ivan-the-terrible\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mountcount\"><img src=\"https://avatars.githubusercontent.com/u/166301065?v=4?s=100\" width=\"100px;\" alt=\"mountcount\"/><br /><sub><b>mountcount</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mountcount\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Bondrake\"><img src=\"https://avatars.githubusercontent.com/u/11696?v=4?s=100\" width=\"100px;\" alt=\"Bondrake\"/><br /><sub><b>Bondrake</b></sub></a><br /><a href=\"#design-Bondrake\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Bondrake\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/R00dRallec\"><img src=\"https://avatars.githubusercontent.com/u/9081954?v=4?s=100\" width=\"100px;\" alt=\"R00dRallec\"/><br /><sub><b>R00dRallec</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=R00dRallec\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=R00dRallec\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/publicfacingusername\"><img src=\"https://avatars.githubusercontent.com/u/13956145?v=4?s=100\" width=\"100px;\" alt=\"Justin Wolfington\"/><br /><sub><b>Justin Wolfington</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=publicfacingusername\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://bio.link/jacktracey\"><img src=\"https://avatars.githubusercontent.com/u/41163455?v=4?s=100\" width=\"100px;\" alt=\"Jack Tracey\"/><br /><sub><b>Jack Tracey</b></sub></a><br /><a href=\"#design-jtracey93\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MarkDaveny\"><img src=\"https://avatars.githubusercontent.com/u/168091250?v=4?s=100\" width=\"100px;\" alt=\"MarkDaveny\"/><br /><sub><b>MarkDaveny</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MarkDaveny\" title=\"Code\">💻</a> <a href=\"#design-MarkDaveny\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MarkDaveny\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.tiwahu.com/\"><img src=\"https://avatars.githubusercontent.com/u/590564?v=4?s=100\" width=\"100px;\" alt=\"Timothy Huber\"/><br /><sub><b>Timothy Huber</b></sub></a><br /><a href=\"#design-tiwahu\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yashjmistry.me\"><img src=\"https://avatars.githubusercontent.com/u/63824041?v=4?s=100\" width=\"100px;\" alt=\"Yash Mistry\"/><br /><sub><b>Yash Mistry</b></sub></a><br /><a href=\"#design-YashJM\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jlabonski\"><img src=\"https://avatars.githubusercontent.com/u/2981369?v=4?s=100\" width=\"100px;\" alt=\"Jeffrey Labonski\"/><br /><sub><b>Jeffrey Labonski</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jlabonski\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jlabonski\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/herbygillot\"><img src=\"https://avatars.githubusercontent.com/u/618376?v=4?s=100\" width=\"100px;\" alt=\"Herby Gillot\"/><br /><sub><b>Herby Gillot</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=herbygillot\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/arjan-s\"><img src=\"https://avatars.githubusercontent.com/u/10400299?v=4?s=100\" width=\"100px;\" alt=\"arjan-s\"/><br /><sub><b>arjan-s</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=arjan-s\" title=\"Code\">💻</a> <a href=\"#design-arjan-s\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=arjan-s\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0323pin\"><img src=\"https://avatars.githubusercontent.com/u/90570748?v=4?s=100\" width=\"100px;\" alt=\"pin\"/><br /><sub><b>pin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=0323pin\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://fireis.dev\"><img src=\"https://avatars.githubusercontent.com/u/109556932?v=4?s=100\" width=\"100px;\" alt=\"FireIsGood\"/><br /><sub><b>FireIsGood</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=FireIsGood\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=FireIsGood\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Joxtacy\"><img src=\"https://avatars.githubusercontent.com/u/10127673?v=4?s=100\" width=\"100px;\" alt=\"Jesper Hasselquist\"/><br /><sub><b>Jesper Hasselquist</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Joxtacy\" title=\"Code\">💻</a> <a href=\"#design-Joxtacy\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Joxtacy\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.aaron-powell.com\"><img src=\"https://avatars.githubusercontent.com/u/434140?v=4?s=100\" width=\"100px;\" alt=\"Aaron Powell\"/><br /><sub><b>Aaron Powell</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=aaronpowell\" title=\"Code\">💻</a> <a href=\"#design-aaronpowell\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=aaronpowell\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Dartypier\"><img src=\"https://avatars.githubusercontent.com/u/22201626?v=4?s=100\" width=\"100px;\" alt=\"Jacopo Zecchi\"/><br /><sub><b>Jacopo Zecchi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Dartypier\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/rose-m\"><img src=\"https://avatars.githubusercontent.com/u/4354632?v=4?s=100\" width=\"100px;\" alt=\"Michael Rose\"/><br /><sub><b>Michael Rose</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rose-m\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rose-m\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://denehoffman.com\"><img src=\"https://avatars.githubusercontent.com/u/36977879?v=4?s=100\" width=\"100px;\" alt=\"Nathaniel D. Hoffman\"/><br /><sub><b>Nathaniel D. Hoffman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=denehoffman\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=denehoffman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://schwobe.dev\"><img src=\"https://avatars.githubusercontent.com/u/926242?v=4?s=100\" width=\"100px;\" alt=\"Michael Schwobe\"/><br /><sub><b>Michael Schwobe</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=michaelschwobe\" title=\"Code\">💻</a> <a href=\"#design-michaelschwobe\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=michaelschwobe\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Nibodhika\"><img src=\"https://avatars.githubusercontent.com/u/729967?v=4?s=100\" width=\"100px;\" alt=\"Nibodhika\"/><br /><sub><b>Nibodhika</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Nibodhika\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Nibodhika\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://davidsass.io\"><img src=\"https://avatars.githubusercontent.com/u/10754765?v=4?s=100\" width=\"100px;\" alt=\"David Sass\"/><br /><sub><b>David Sass</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sassdawe\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.carehart.org\"><img src=\"https://avatars.githubusercontent.com/u/389746?v=4?s=100\" width=\"100px;\" alt=\"Charlie Arehart\"/><br /><sub><b>Charlie Arehart</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=carehart\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/aramikuto\"><img src=\"https://avatars.githubusercontent.com/u/116561995?v=4?s=100\" width=\"100px;\" alt=\"Aleksandr Kondrashov\"/><br /><sub><b>Aleksandr Kondrashov</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=aramikuto\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://jacobbundgaard.dk\"><img src=\"https://avatars.githubusercontent.com/u/984760?v=4?s=100\" width=\"100px;\" alt=\"Jacob Bundgaard\"/><br /><sub><b>Jacob Bundgaard</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kimsey0\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://thisaru.me\"><img src=\"https://avatars.githubusercontent.com/u/40016057?v=4?s=100\" width=\"100px;\" alt=\"Thisaru Guruge\"/><br /><sub><b>Thisaru Guruge</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ThisaruGuruge\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/edwin-shdw\"><img src=\"https://avatars.githubusercontent.com/u/62764562?v=4?s=100\" width=\"100px;\" alt=\"Edwin\"/><br /><sub><b>Edwin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=edwin-shdw\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://dickinson.id\"><img src=\"https://avatars.githubusercontent.com/u/522465?v=4?s=100\" width=\"100px;\" alt=\"Jonathan Dickinson\"/><br /><sub><b>Jonathan Dickinson</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jcdickinson\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/po1o\"><img src=\"https://avatars.githubusercontent.com/u/5702825?v=4?s=100\" width=\"100px;\" alt=\"Polo-François Poli\"/><br /><sub><b>Polo-François Poli</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=po1o\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/EDIflyer\"><img src=\"https://avatars.githubusercontent.com/u/13610277?v=4?s=100\" width=\"100px;\" alt=\"EDIflyer\"/><br /><sub><b>EDIflyer</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=EDIflyer\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=EDIflyer\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://felipezorzo.com.br\"><img src=\"https://avatars.githubusercontent.com/u/13829?v=4?s=100\" width=\"100px;\" alt=\"Felipe Zorzo\"/><br /><sub><b>Felipe Zorzo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=felipebz\" title=\"Code\">💻</a> <a href=\"#design-felipebz\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=felipebz\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/DeepSpace2\"><img src=\"https://avatars.githubusercontent.com/u/6841988?v=4?s=100\" width=\"100px;\" alt=\"Adi Vaknin\"/><br /><sub><b>Adi Vaknin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=DeepSpace2\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=DeepSpace2\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://leevs.dev/\"><img src=\"https://avatars.githubusercontent.com/u/835319?v=4?s=100\" width=\"100px;\" alt=\"Elad Leev\"/><br /><sub><b>Elad Leev</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=EladLeev\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=EladLeev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Soyvolon\"><img src=\"https://avatars.githubusercontent.com/u/16871668?v=4?s=100\" width=\"100px;\" alt=\"Bounds\"/><br /><sub><b>Bounds</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Soyvolon\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Soyvolon\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://yashgarg.dev\"><img src=\"https://avatars.githubusercontent.com/u/33605526?v=4?s=100\" width=\"100px;\" alt=\"Yash Garg\"/><br /><sub><b>Yash Garg</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Yash-Garg\" title=\"Code\">💻</a> <a href=\"#design-Yash-Garg\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Yash-Garg\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sarpuser\"><img src=\"https://avatars.githubusercontent.com/u/23362324?v=4?s=100\" width=\"100px;\" alt=\"Sarp User\"/><br /><sub><b>Sarp User</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sarpuser\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sarpuser\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/clemyan\"><img src=\"https://avatars.githubusercontent.com/u/41266433?v=4?s=100\" width=\"100px;\" alt=\"Clement Yan\"/><br /><sub><b>Clement Yan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=clemyan\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/thep0y\"><img src=\"https://avatars.githubusercontent.com/u/51874567?v=4?s=100\" width=\"100px;\" alt=\"thep0y\"/><br /><sub><b>thep0y</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=thep0y\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ClxUne09\"><img src=\"https://avatars.githubusercontent.com/u/175628107?v=4?s=100\" width=\"100px;\" alt=\"Artin\"/><br /><sub><b>Artin</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ClxUne09\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ClxUne09\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/guspan-tanadi\"><img src=\"https://avatars.githubusercontent.com/u/36249910?v=4?s=100\" width=\"100px;\" alt=\"Guspan Tanadi\"/><br /><sub><b>Guspan Tanadi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=guspan-tanadi\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://vivosys.com\"><img src=\"https://avatars.githubusercontent.com/u/53049?v=4?s=100\" width=\"100px;\" alt=\"Raman Gupta\"/><br /><sub><b>Raman Gupta</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=rocketraman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/hsnabszhdn\"><img src=\"https://avatars.githubusercontent.com/u/16090309?v=4?s=100\" width=\"100px;\" alt=\"Hossein Abbasi\"/><br /><sub><b>Hossein Abbasi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=hsnabszhdn\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kizivat.eu\"><img src=\"https://avatars.githubusercontent.com/u/3535926?v=4?s=100\" width=\"100px;\" alt=\"David Kizivat\"/><br /><sub><b>David Kizivat</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kizivat\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kizivat\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mgrubb\"><img src=\"https://avatars.githubusercontent.com/u/351301?v=4?s=100\" width=\"100px;\" alt=\"Michael Grubb\"/><br /><sub><b>Michael Grubb</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mgrubb\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/oliviaBahr\"><img src=\"https://avatars.githubusercontent.com/u/98684296?v=4?s=100\" width=\"100px;\" alt=\"Olivia Bahr\"/><br /><sub><b>Olivia Bahr</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=oliviaBahr\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=oliviaBahr\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/garysassano\"><img src=\"https://avatars.githubusercontent.com/u/10464497?v=4?s=100\" width=\"100px;\" alt=\"Gary Sassano\"/><br /><sub><b>Gary Sassano</b></sub></a><br /><a href=\"#design-garysassano\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ilaumjd\"><img src=\"https://avatars.githubusercontent.com/u/16514431?v=4?s=100\" width=\"100px;\" alt=\"Ilham AM\"/><br /><sub><b>Ilham AM</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ilaumjd\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ilaumjd\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://trajano.net/\"><img src=\"https://avatars.githubusercontent.com/u/110627?v=4?s=100\" width=\"100px;\" alt=\"Archimedes Trajano\"/><br /><sub><b>Archimedes Trajano</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=trajano\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/devxpain\"><img src=\"https://avatars.githubusercontent.com/u/170700110?v=4?s=100\" width=\"100px;\" alt=\"devxpain\"/><br /><sub><b>devxpain</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=devxpain\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.antonin-ruan.fr\"><img src=\"https://avatars.githubusercontent.com/u/43148004?v=4?s=100\" width=\"100px;\" alt=\"Antonin Ruan\"/><br /><sub><b>Antonin Ruan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AntoninRuan\" title=\"Code\">💻</a> <a href=\"#design-AntoninRuan\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=AntoninRuan\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/00ll00\"><img src=\"https://avatars.githubusercontent.com/u/40747228?v=4?s=100\" width=\"100px;\" alt=\"00ll00\"/><br /><sub><b>00ll00</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=00ll00\" title=\"Code\">💻</a> <a href=\"#design-00ll00\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=00ll00\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://devnotes.ernstc.net/\"><img src=\"https://avatars.githubusercontent.com/u/130360?v=4?s=100\" width=\"100px;\" alt=\"Ernesto Cianciotta\"/><br /><sub><b>Ernesto Cianciotta</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ernstc\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ernstc\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/eelispeltola\"><img src=\"https://avatars.githubusercontent.com/u/15069074?v=4?s=100\" width=\"100px;\" alt=\"Eelis Peltola\"/><br /><sub><b>Eelis Peltola</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=eelispeltola\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vshulcz\"><img src=\"https://avatars.githubusercontent.com/u/99616188?v=4?s=100\" width=\"100px;\" alt=\"Vlad Shulcz\"/><br /><sub><b>Vlad Shulcz</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=vshulcz\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Silzinc\"><img src=\"https://avatars.githubusercontent.com/u/128738169?v=4?s=100\" width=\"100px;\" alt=\"Silzinc\"/><br /><sub><b>Silzinc</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Silzinc\" title=\"Code\">💻</a> <a href=\"#design-Silzinc\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Silzinc\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Hampter\"><img src=\"https://avatars.githubusercontent.com/u/23213489?v=4?s=100\" width=\"100px;\" alt=\"Noah Springer\"/><br /><sub><b>Noah Springer</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Hampter\" title=\"Code\">💻</a> <a href=\"#design-Hampter\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Hampter\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dusktreader\"><img src=\"https://avatars.githubusercontent.com/u/713676?v=4?s=100\" width=\"100px;\" alt=\"Tucker Beck\"/><br /><sub><b>Tucker Beck</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dusktreader\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dusktreader\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://mpb-dev.fr/\"><img src=\"https://avatars.githubusercontent.com/u/38607067?v=4?s=100\" width=\"100px;\" alt=\"Sunshio\"/><br /><sub><b>Sunshio</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Pietrucci-Blacher\" title=\"Code\">💻</a> <a href=\"#design-Pietrucci-Blacher\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Pietrucci-Blacher\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://pashagolub.github.io/blog\"><img src=\"https://avatars.githubusercontent.com/u/9463113?v=4?s=100\" width=\"100px;\" alt=\"Pavlo Golub\"/><br /><sub><b>Pavlo Golub</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=pashagolub\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://heaths.dev\"><img src=\"https://avatars.githubusercontent.com/u/1532486?v=4?s=100\" width=\"100px;\" alt=\"Heath Stewart\"/><br /><sub><b>Heath Stewart</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=heaths\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://xelph.me\"><img src=\"https://avatars.githubusercontent.com/u/29693543?v=4?s=100\" width=\"100px;\" alt=\"Xelph\"/><br /><sub><b>Xelph</b></sub></a><br /><a href=\"#design-HypheX\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://tristanleclair.github.io/personal-website/index.html\"><img src=\"https://avatars.githubusercontent.com/u/60434271?v=4?s=100\" width=\"100px;\" alt=\"Tristan Leclair-Vani\"/><br /><sub><b>Tristan Leclair-Vani</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=TristanLeclair\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/vil02\"><img src=\"https://avatars.githubusercontent.com/u/65706193?v=4?s=100\" width=\"100px;\" alt=\"Piotr Idzik\"/><br /><sub><b>Piotr Idzik</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=vil02\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://wiyco.dev\"><img src=\"https://avatars.githubusercontent.com/u/72733890?v=4?s=100\" width=\"100px;\" alt=\"wiyco\"/><br /><sub><b>wiyco</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=wiyco\" title=\"Code\">💻</a> <a href=\"#design-wiyco\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=wiyco\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/abhro\"><img src=\"https://avatars.githubusercontent.com/u/5664668?v=4?s=100\" width=\"100px;\" alt=\"abhro\"/><br /><sub><b>abhro</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=abhro\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://sharepointgurus.net\"><img src=\"https://avatars.githubusercontent.com/u/25376734?v=4?s=100\" width=\"100px;\" alt=\"Ivan Wilson\"/><br /><sub><b>Ivan Wilson</b></sub></a><br /><a href=\"#design-spg-iwilson\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mdanish-kh\"><img src=\"https://avatars.githubusercontent.com/u/88161975?v=4?s=100\" width=\"100px;\" alt=\"Muhammad Danish\"/><br /><sub><b>Muhammad Danish</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mdanish-kh\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://dub.sh/boscodomingo\"><img src=\"https://avatars.githubusercontent.com/u/46006784?v=4?s=100\" width=\"100px;\" alt=\"Bosco Domingo\"/><br /><sub><b>Bosco Domingo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=BoscoDomingo\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://edu4rdshl.dev\"><img src=\"https://avatars.githubusercontent.com/u/32582878?v=4?s=100\" width=\"100px;\" alt=\"Eduard Tolosa\"/><br /><sub><b>Eduard Tolosa</b></sub></a><br /><a href=\"#design-Edu4rdSHL\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Edu4rdSHL\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JamesAndrewJackson13\"><img src=\"https://avatars.githubusercontent.com/u/27647566?v=4?s=100\" width=\"100px;\" alt=\"James Jackson\"/><br /><sub><b>James Jackson</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=JamesAndrewJackson13\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=JamesAndrewJackson13\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Mr-Vipi\"><img src=\"https://avatars.githubusercontent.com/u/58825526?v=4?s=100\" width=\"100px;\" alt=\"Jul Guga\"/><br /><sub><b>Jul Guga</b></sub></a><br /><a href=\"#design-Mr-Vipi\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://txzhan.io\"><img src=\"https://avatars.githubusercontent.com/u/178074436?v=4?s=100\" width=\"100px;\" alt=\"tiaoxizhan\"/><br /><sub><b>tiaoxizhan</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=tiaoxizhan\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/chrisant996\"><img src=\"https://avatars.githubusercontent.com/u/17440311?v=4?s=100\" width=\"100px;\" alt=\"Chris Antos\"/><br /><sub><b>Chris Antos</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=chrisant996\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://robertbleattler.com\"><img src=\"https://avatars.githubusercontent.com/u/40604784?v=4?s=100\" width=\"100px;\" alt=\"Robert Bleattler\"/><br /><sub><b>Robert Bleattler</b></sub></a><br /><a href=\"#design-rbleattler\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://artis-auxilium.fr/fr\"><img src=\"https://avatars.githubusercontent.com/u/1815655?v=4?s=100\" width=\"100px;\" alt=\"dev2a\"/><br /><sub><b>dev2a</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=d3v2a\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://gardunos.tech\"><img src=\"https://avatars.githubusercontent.com/u/30121656?v=4?s=100\" width=\"100px;\" alt=\"Luis\"/><br /><sub><b>Luis</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=luisegarduno\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/tleepa\"><img src=\"https://avatars.githubusercontent.com/u/7734919?v=4?s=100\" width=\"100px;\" alt=\"Leepa\"/><br /><sub><b>Leepa</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=tleepa\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=tleepa\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.raylu.net\"><img src=\"https://avatars.githubusercontent.com/u/90059?v=4?s=100\" width=\"100px;\" alt=\"raylu\"/><br /><sub><b>raylu</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=raylu\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=raylu\" title=\"Documentation\">📖</a> <a href=\"#design-raylu\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/lechwolowski\"><img src=\"https://avatars.githubusercontent.com/u/33866950?v=4?s=100\" width=\"100px;\" alt=\"Lech Wołowski\"/><br /><sub><b>Lech Wołowski</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=lechwolowski\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/OwlBurst\"><img src=\"https://avatars.githubusercontent.com/u/158167545?v=4?s=100\" width=\"100px;\" alt=\"Owl Burst\"/><br /><sub><b>Owl Burst</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=OwlBurst\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://rubixdev.de\"><img src=\"https://avatars.githubusercontent.com/u/35602040?v=4?s=100\" width=\"100px;\" alt=\"Silas Groh\"/><br /><sub><b>Silas Groh</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=RubixDev\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=RubixDev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://mwiede.me/blog\"><img src=\"https://avatars.githubusercontent.com/u/4295189?v=4?s=100\" width=\"100px;\" alt=\"Marco Wiedemeyer\"/><br /><sub><b>Marco Wiedemeyer</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mwiedemeyer\" title=\"Code\">💻</a> <a href=\"#design-mwiedemeyer\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mwiedemeyer\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/0-0-1-0-1-0-1-0\"><img src=\"https://avatars.githubusercontent.com/u/43226073?v=4?s=100\" width=\"100px;\" alt=\"0-0-1-0-1-0-1-0\"/><br /><sub><b>0-0-1-0-1-0-1-0</b></sub></a><br /><a href=\"#design-0-0-1-0-1-0-1-0\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/player131007\"><img src=\"https://avatars.githubusercontent.com/u/77326303?v=4?s=100\" width=\"100px;\" alt=\"player131007\"/><br /><sub><b>player131007</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=player131007\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kaien07\"><img src=\"https://avatars.githubusercontent.com/u/160471571?v=4?s=100\" width=\"100px;\" alt=\"kaien07\"/><br /><sub><b>kaien07</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kaien07\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/BusHero\"><img src=\"https://avatars.githubusercontent.com/u/24370515?v=4?s=100\" width=\"100px;\" alt=\"Cervac Petru\"/><br /><sub><b>Cervac Petru</b></sub></a><br /><a href=\"#design-BusHero\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Marukome0743\"><img src=\"https://avatars.githubusercontent.com/u/146040408?v=4?s=100\" width=\"100px;\" alt=\"マルコメ\"/><br /><sub><b>マルコメ</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Marukome0743\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Marukome0743\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mreinhardt\"><img src=\"https://avatars.githubusercontent.com/u/582461?v=4?s=100\" width=\"100px;\" alt=\"Michael Reinhardt\"/><br /><sub><b>Michael Reinhardt</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mreinhardt\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mreinhardt\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/AspectBruise09\"><img src=\"https://avatars.githubusercontent.com/u/141767586?v=4?s=100\" width=\"100px;\" alt=\"Artin\"/><br /><sub><b>Artin</b></sub></a><br /><a href=\"#design-AspectBruise09\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://bsimjoo.pcworms.ir\"><img src=\"https://avatars.githubusercontent.com/u/117530839?v=4?s=100\" width=\"100px;\" alt=\"Behnam Simjoo\"/><br /><sub><b>Behnam Simjoo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=b-simjoo\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/plamendelchev\"><img src=\"https://avatars.githubusercontent.com/u/25668366?v=4?s=100\" width=\"100px;\" alt=\"Plamen Delchev\"/><br /><sub><b>Plamen Delchev</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=plamendelchev\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=plamendelchev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/beaualbritton\"><img src=\"https://avatars.githubusercontent.com/u/112587801?v=4?s=100\" width=\"100px;\" alt=\"beau albritton\"/><br /><sub><b>beau albritton</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=beaualbritton\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://note-of-me.top\"><img src=\"https://avatars.githubusercontent.com/u/29329988?v=4?s=100\" width=\"100px;\" alt=\"Cierra-Runis\"/><br /><sub><b>Cierra-Runis</b></sub></a><br /><a href=\"#design-Cierra-Runis\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jasonm23\"><img src=\"https://avatars.githubusercontent.com/u/71587?v=4?s=100\" width=\"100px;\" alt=\"Jason Milkins\"/><br /><sub><b>Jason Milkins</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=jasonm23\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://www.arb.dev\"><img src=\"https://avatars.githubusercontent.com/u/20059577?v=4?s=100\" width=\"100px;\" alt=\"arjunrbery\"/><br /><sub><b>arjunrbery</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=arjunrbery\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/JamBalaya56562\"><img src=\"https://avatars.githubusercontent.com/u/88115388?v=4?s=100\" width=\"100px;\" alt=\"Jam Balaya\"/><br /><sub><b>Jam Balaya</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=JamBalaya56562\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=JamBalaya56562\" title=\"Code\">💻</a> <a href=\"#design-JamBalaya56562\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/RichLewis007\"><img src=\"https://avatars.githubusercontent.com/u/1149213?v=4?s=100\" width=\"100px;\" alt=\"Rich Lewis\"/><br /><sub><b>Rich Lewis</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=RichLewis007\" title=\"Documentation\">📖</a> <a href=\"#design-RichLewis007\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://gijsreijn.medium.com/\"><img src=\"https://avatars.githubusercontent.com/u/26114636?v=4?s=100\" width=\"100px;\" alt=\"Gijs Reijn\"/><br /><sub><b>Gijs Reijn</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Gijsreyn\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Gijsreyn\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://mikel.olasagasti.info\"><img src=\"https://avatars.githubusercontent.com/u/773148?v=4?s=100\" width=\"100px;\" alt=\"Mikel Olasagasti Uranga\"/><br /><sub><b>Mikel Olasagasti Uranga</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mikelolasagasti\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/mkvlrn\"><img src=\"https://avatars.githubusercontent.com/u/186238078?v=4?s=100\" width=\"100px;\" alt=\"mkvlrn\"/><br /><sub><b>mkvlrn</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mkvlrn\" title=\"Code\">💻</a> <a href=\"#design-mkvlrn\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=mkvlrn\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://iandunn.name\"><img src=\"https://avatars.githubusercontent.com/u/484068?v=4?s=100\" width=\"100px;\" alt=\"Ian Dunn\"/><br /><sub><b>Ian Dunn</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=iandunn\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sanki92\"><img src=\"https://avatars.githubusercontent.com/u/70330866?v=4?s=100\" width=\"100px;\" alt=\"Sankalp Tripathi\"/><br /><sub><b>Sankalp Tripathi</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sanki92\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sanki92\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/PSModule\"><img src=\"https://avatars.githubusercontent.com/u/17722253?v=4?s=100\" width=\"100px;\" alt=\"Marius Storhaug\"/><br /><sub><b>Marius Storhaug</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MariusStorhaug\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ADIX7\"><img src=\"https://avatars.githubusercontent.com/u/10939090?v=4?s=100\" width=\"100px;\" alt=\"Kovács Ádám\"/><br /><sub><b>Kovács Ádám</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ADIX7\" title=\"Documentation\">📖</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ADIX7\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.edoyen.com/\"><img src=\"https://avatars.githubusercontent.com/u/7102007?v=4?s=100\" width=\"100px;\" alt=\"Enzo Doyen\"/><br /><sub><b>Enzo Doyen</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=spidersouris\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://pinta.land\"><img src=\"https://avatars.githubusercontent.com/u/19735646?v=4?s=100\" width=\"100px;\" alt=\"Pinta\"/><br /><sub><b>Pinta</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Pinta365\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Pinta365\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/scop\"><img src=\"https://avatars.githubusercontent.com/u/109152?v=4?s=100\" width=\"100px;\" alt=\"Ville Skyttä\"/><br /><sub><b>Ville Skyttä</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=scop\" title=\"Code\">💻</a> <a href=\"#design-scop\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=scop\" title=\"Documentation\">📖</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://linkedin.com/in/anujsays\"><img src=\"https://avatars.githubusercontent.com/u/1001682?v=4?s=100\" width=\"100px;\" alt=\"Anuj Kumar\"/><br /><sub><b>Anuj Kumar</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=anujsrc\" title=\"Code\">💻</a> <a href=\"#design-anujsrc\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=anujsrc\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/ValerioCeccarelli\"><img src=\"https://avatars.githubusercontent.com/u/42637334?v=4?s=100\" width=\"100px;\" alt=\"Valerio Ceccarelli\"/><br /><sub><b>Valerio Ceccarelli</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=ValerioCeccarelli\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/jvsca\"><img src=\"https://avatars.githubusercontent.com/u/2821731?v=4?s=100\" width=\"100px;\" alt=\"Juan Svaikauskas\"/><br /><sub><b>Juan Svaikauskas</b></sub></a><br /><a href=\"#design-jvsca\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/johnstegeman/\"><img src=\"https://avatars.githubusercontent.com/u/6601691?v=4?s=100\" width=\"100px;\" alt=\"John Stegeman\"/><br /><sub><b>John Stegeman</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=johnstegeman\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=johnstegeman\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/gorfey\"><img src=\"https://avatars.githubusercontent.com/u/39035228?v=4?s=100\" width=\"100px;\" alt=\"Luke Van De Weghe\"/><br /><sub><b>Luke Van De Weghe</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=gorfey\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/stmach\"><img src=\"https://avatars.githubusercontent.com/u/33124232?v=4?s=100\" width=\"100px;\" alt=\"Stefan Mach\"/><br /><sub><b>Stefan Mach</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=stmach\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://squaricdot.com\"><img src=\"https://avatars.githubusercontent.com/u/4513505?v=4?s=100\" width=\"100px;\" alt=\"Olmo Rupert\"/><br /><sub><b>Olmo Rupert</b></sub></a><br /><a href=\"#design-squaricdot\" title=\"Design\">🎨</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/IsaacFG2\"><img src=\"https://avatars.githubusercontent.com/u/147211323?v=4?s=100\" width=\"100px;\" alt=\"IsaacFG2\"/><br /><sub><b>IsaacFG2</b></sub></a><br /><a href=\"#design-IsaacFG2\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/kostadin-tonchekliev\"><img src=\"https://avatars.githubusercontent.com/u/95169764?v=4?s=100\" width=\"100px;\" alt=\"Kostadin Tonchekliev\"/><br /><sub><b>Kostadin Tonchekliev</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kostadin-tonchekliev\" title=\"Code\">💻</a> <a href=\"#design-kostadin-tonchekliev\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kostadin-tonchekliev\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/soroshsabz\"><img src=\"https://avatars.githubusercontent.com/u/17947618?v=4?s=100\" width=\"100px;\" alt=\"soroshsabz\"/><br /><sub><b>soroshsabz</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=soroshsabz\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://blog.toenn-vaot.fr\"><img src=\"https://avatars.githubusercontent.com/u/60755917?v=4?s=100\" width=\"100px;\" alt=\"Yoann BLOSSIER\"/><br /><sub><b>Yoann BLOSSIER</b></sub></a><br /><a href=\"#design-yblossier\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://kvokka.github.io/\"><img src=\"https://avatars.githubusercontent.com/u/15954013?v=4?s=100\" width=\"100px;\" alt=\"Mikhail Beliakov\"/><br /><sub><b>Mikhail Beliakov</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kvokka\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=kvokka\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/MrRainbow0704\"><img src=\"https://avatars.githubusercontent.com/u/95081253?v=4?s=100\" width=\"100px;\" alt=\"Marco Simone\"/><br /><sub><b>Marco Simone</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MrRainbow0704\" title=\"Code\">💻</a> <a href=\"#design-MrRainbow0704\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=MrRainbow0704\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/sbeardsley\"><img src=\"https://avatars.githubusercontent.com/u/6288131?v=4?s=100\" width=\"100px;\" alt=\"sbeardsley\"/><br /><sub><b>sbeardsley</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=sbeardsley\" title=\"Code\">💻</a></td>\n    </tr>\n    <tr>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://www.linkedin.com/in/maxvictor\"><img src=\"https://avatars.githubusercontent.com/u/11591713?v=4?s=100\" width=\"100px;\" alt=\"Max Victor\"/><br /><sub><b>Max Victor</b></sub></a><br /><a href=\"#design-maxvictor\" title=\"Design\">🎨</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/adackny\"><img src=\"https://avatars.githubusercontent.com/u/61998238?v=4?s=100\" width=\"100px;\" alt=\"Adackny Castillo\"/><br /><sub><b>Adackny Castillo</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=adackny\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=adackny\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/aeriondyseti\"><img src=\"https://avatars.githubusercontent.com/u/24901014?v=4?s=100\" width=\"100px;\" alt=\"K Whiteside\"/><br /><sub><b>K Whiteside</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=aeriondyseti\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"http://dadahsueh.vercel.app\"><img src=\"https://avatars.githubusercontent.com/u/26140722?v=4?s=100\" width=\"100px;\" alt=\"Dada Hsueh\"/><br /><sub><b>Dada Hsueh</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dadahsueh\" title=\"Code\">💻</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/dohzya\"><img src=\"https://avatars.githubusercontent.com/u/9595?v=4?s=100\" width=\"100px;\" alt=\"Étienne Vallette d'Osia\"/><br /><sub><b>Étienne Vallette d'Osia</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dohzya\" title=\"Code\">💻</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=dohzya\" title=\"Documentation\">📖</a></td>\n      <td align=\"center\" valign=\"top\" width=\"14.28%\"><a href=\"https://github.com/Eckii24\"><img src=\"https://avatars.githubusercontent.com/u/35373554?v=4?s=100\" width=\"100px;\" alt=\"Eckii24\"/><br /><sub><b>Eckii24</b></sub></a><br /><a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Eckii24\" title=\"Code\">💻</a> <a href=\"#design-Eckii24\" title=\"Design\">🎨</a> <a href=\"https://github.com/JanDeDobbeleer/oh-my-posh/commits?author=Eckii24\" title=\"Documentation\">📖</a></td>\n    </tr>\n  </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors][ac] specification.\nContributions of any kind welcome!\n\n[acek]: https://allcontributors.org/docs/en/emoji-key\n[ac]: https://github.com/all-contributors/all-contributors\n"
  },
  {
    "path": "website/docs/dsc.md",
    "content": "---\nid: dsc\ntitle: Desired State Configuration\nsidebar_label: 🖥️ Desired State Configuration\n---\n\nOh My Posh supports Desired State Configuration (DSC) for declarative configuration management, enabling automated\ndeployment and consistent configuration across multiple systems.\n\n## Concept\n\nOh My Posh DSC builds on the traditional Oh My Posh configuration approach by adding automation and orchestration\ncapabilities. Instead of manually configuring your prompt, you can define the desired state declaratively and let DSC\nensure your system matches that state.\n\nDSC works with **resources** that represent different aspects of your Oh My Posh setup:\n\n- **Configuration Resource**: Manages your Oh My Posh configuration files\n- **Shell Resource**: Handles shell initialization and integration\n- **Font Resource**: Tracks installed Nerd Fonts\n\nThese resources can be used standalone through the CLI or integrated with orchestration tools like WinGet and\nMicrosoft DSC for automated deployments.\n\n## Overview\n\nDSC support in Oh My Posh provides:\n\n- **Declarative configuration**: Define the desired state of your Oh My Posh setup\n- **Automated deployment**: Configure Oh My Posh as part of system provisioning workflows\n- **Shell integration**: Automatically configure shell initialization for bash, zsh, fish, PowerShell, and more\n- **Font management**: Track installed Nerd Fonts through DSC state\n- **Orchestration support**: Integration with WinGet and Microsoft DSC tools\n\nDSC functionality is available through the `oh-my-posh` CLI and can be used standalone or with orchestration tools.\n\n## DSC Resources\n\nOh My Posh provides the following DSC resources:\n\n### Configuration Resource\n\nManages Oh My Posh configuration files.\n\n**Operations**: `get`, `set`, `export`, `schema`\n\n```bash\n# Get current configuration state\noh-my-posh config dsc get\n\n# Apply a configuration\noh-my-posh config dsc set --state '{\"states\":[{\"source\":\"~/mytheme.omp.json\",\"format\":\"json\"}]}'\n\n# Get configuration schema\noh-my-posh config dsc schema\n```\n\n### Shell Resource\n\nManages shell initialization and integration.\n\n**Operations**: `get`, `set`, `export`, `schema`\n\n```bash\n# Get current shell configurations\noh-my-posh init bash dsc get\n\n# Configure shell initialization\noh-my-posh init bash dsc set --state '{\"states\":[{\"name\":\"bash\",\"command\":\"oh-my-posh init bash --config ~/mytheme.omp.json\"}]}'\n```\n\n### Font Resource\n\nTracks Nerd Fonts installed through Oh My Posh.\n\n**Operations**: `get`, `export`, `schema`\n\n```bash\n# Get installed fonts\noh-my-posh font dsc get\n\n# Get font schema\noh-my-posh font dsc schema\n```\n\n## Direct CLI Usage\n\nYou can use the DSC commands directly from the command line for configuration management.\n\n### Managing Configurations\n\n#### Get State\n\nRetrieve the current configuration state:\n\n```bash\noh-my-posh config dsc get\n```\n\nExample output:\n\n```json\n{\n  \"states\": [\n    {\n      \"format\": \"json\",\n      \"source\": \"~/mytheme.omp.json\"\n    }\n  ]\n}\n```\n\n#### Set State\n\nApply a new configuration state:\n\n```bash\noh-my-posh config dsc set --state '{\"states\":[{\"source\":\"~/mytheme.omp.json\",\"format\":\"json\"}]}'\n```\n\nThis creates or updates the configuration file at the specified location with the provided format.\n\n#### Schema\n\nGet the JSON schema for the configuration resource:\n\n```bash\noh-my-posh config dsc schema\n```\n\nUse this to understand the structure and available options for configuration states.\n\n### Managing shell Integration\n\n#### Bash\n\nConfigure Oh My Posh initialization for bash:\n\n```bash\n# Get current state\noh-my-posh init bash dsc get\n\n# Set initialization\noh-my-posh init bash dsc set --state '{\"states\":[{\"name\":\"bash\",\"command\":\"oh-my-posh init bash --config ~/mytheme.omp.json\"}]}'\n```\n\nThis automatically updates your `.bashrc` or `.bash_profile` with the Oh My Posh initialization command.\n\n#### Zsh\n\nConfigure Oh My Posh initialization for zsh:\n\n```bash\n# Get current state\noh-my-posh init zsh dsc get\n\n# Set initialization\noh-my-posh init zsh dsc set --state '{\"states\":[{\"name\":\"zsh\",\"command\":\"oh-my-posh init zsh --config ~/mytheme.omp.json\"}]}'\n```\n\nThis automatically updates your `.zshrc` with the Oh My Posh initialization command.\n\n#### PowerShell\n\nConfigure Oh My Posh initialization for PowerShell:\n\n```powershell\n# Get current state\noh-my-posh init pwsh dsc get\n\n# Set initialization\noh-my-posh init pwsh dsc set --state '{\"states\":[{\"name\":\"pwsh\",\"command\":\"oh-my-posh init pwsh --config ~/mytheme.omp.json\"}]}'\n```\n\nThis automatically updates your PowerShell profile with the Oh My Posh initialization command.\n\n#### Fish\n\nConfigure Oh My Posh initialization for fish:\n\n```bash\n# Get current state\noh-my-posh init fish dsc get\n\n# Set initialization\noh-my-posh init fish dsc set --state '{\"states\":[{\"name\":\"fish\",\"command\":\"oh-my-posh init fish --config ~/mytheme.omp.json\"}]}'\n```\n\nThis automatically updates your fish `config.fish` with the Oh My Posh initialization command.\n\n## Orchestration with WinGet\n\nWinGet configuration enables you to install Oh My Posh and apply configuration in a single declarative file.\n\n### Basic WinGet configuration\n\nCreate a configuration file to install and configure Oh My Posh:\n\n```yaml title=\"oh-my-posh-setup.yaml\"\n$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/config/document.json\nmetadata:\n  winget:\n    processor: dscv3\nresources:\n  - name: Install Oh My Posh\n    type: Microsoft.WinGet.DSC/WinGetPackage\n    properties:\n      id: JanDeDobbeleer.OhMyPosh\n      source: winget\n```\n\nApply the configuration:\n\n```powershell\nwinget configure oh-my-posh-setup.yaml\n```\n\n### Complete setup with configuration and shell\n\nThis example installs Oh My Posh, adds your configuration, and initializes PowerShell:\n\n```yaml title=\"oh-my-posh-complete.yaml\"\n$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/config/document.json\nmetadata:\n  winget:\n    processor: dscv3\nresources:\n  - name: Install Oh My Posh\n    type: Microsoft.WinGet.DSC/WinGetPackage\n    properties:\n      id: JanDeDobbeleer.OhMyPosh\n      source: winget\n\n  - name: Add Oh My Posh configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/mytheme.omp.json\n          format: json\n\n  - name: Initialize PowerShell\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: pwsh\n          command: oh-my-posh init pwsh --config ~/mytheme.omp.json\n```\n\nApply with:\n\n```powershell\nwinget configure oh-my-posh-complete.yaml\n```\n\n### Multi-shell configuration\n\nInitialize multiple shells with different configurations:\n\n```yaml title=\"oh-my-posh-multi-shell.yaml\"\n$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/config/document.json\nmetadata:\n  winget:\n    processor: dscv3\nresources:\n  - name: Install Oh My Posh\n    type: Microsoft.WinGet.DSC/WinGetPackage\n    properties:\n      id: JanDeDobbeleer.OhMyPosh\n      source: winget\n\n  - name: Add work configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/work-theme.omp.json\n          format: json\n\n  - name: Add personal configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/personal-theme.omp.json\n          format: json\n\n  - name: Initialize PowerShell with work configuration\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: pwsh\n          command: oh-my-posh init pwsh --config ~/work-theme.omp.json\n\n  - name: Initialize Bash with personal configuration\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: bash\n          command: oh-my-posh init bash --config ~/personal-theme.omp.json\n```\n\n## Orchestration with Microsoft DSC\n\nMicrosoft DSC (`dsc`) provides cross-platform configuration management capabilities. Oh My Posh provides native DSC\nresources that can be used in DSC configuration documents.\n\n### Example DSC configuration\n\nCreate a configuration document for Oh My Posh:\n\n```yaml title=\"oh-my-posh-dsc.yaml\"\n$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json\nresources:\n  - name: Add Oh My Posh configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/mytheme.omp.json\n          format: json\n\n  - name: Initialize PowerShell\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: pwsh\n          command: oh-my-posh init pwsh --config ~/mytheme.omp.json\n```\n\nApply the configuration using the `dsc` CLI:\n\n```bash\ndsc config set --document oh-my-posh-dsc.yaml\n```\n\n### Complete configuration with multiple shells\n\n```yaml title=\"oh-my-posh-complete-dsc.yaml\"\n$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json\nresources:\n  - name: Add primary configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/primary-theme.omp.json\n          format: json\n\n  - name: Add secondary configuration\n    type: OhMyPosh/Config\n    properties:\n      states:\n        - source: ~/secondary-theme.omp.json\n          format: yaml\n\n  - name: Initialize PowerShell\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: pwsh\n          command: oh-my-posh init pwsh --config ~/primary-theme.omp.json\n\n  - name: Initialize Bash\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: bash\n          command: oh-my-posh init bash --config ~/primary-theme.omp.json\n\n  - name: Initialize Zsh\n    type: OhMyPosh/Shell\n    properties:\n      states:\n        - name: zsh\n          command: oh-my-posh init zsh --config ~/secondary-theme.omp.json\n```\n\n### Resource Types\n\nOh My Posh provides the following DSC resource types:\n\n#### OhMyPosh/Config\n\nManages Oh My Posh configuration files.\n\n**Properties:**\n\n- `states` (array): List of configuration states\n  - `source` (string): Path to the configuration file\n  - `format` (string): Format of the configuration file (`json`, `yaml`, `toml`)\n\n#### OhMyPosh/Shell\n\nManages shell initialization.\n\n**Properties:**\n\n- `states` (array): List of shell configurations\n  - `name` (string): Shell name (`bash`, `zsh`, `pwsh`, `fish`, etc.)\n  - `command` (string): Oh My Posh initialization command\n\n#### OhMyPosh/Font\n\nTracks installed Nerd Fonts. This resource is read-only and automatically populated when fonts are installed through\nOh My Posh.\n\n## Configuration State Management\n\nDSC state is stored in the Oh My Posh cache and persists across sessions. This enables:\n\n- **State tracking**: Oh My Posh remembers configurations set through DSC\n- **Idempotency**: Running the same DSC command multiple times produces the same result\n- **State validation**: Query current state before making changes\n\n## Advanced Usage\n\n### Multiple configurations\n\nYou can manage multiple configuration files:\n\n```bash\noh-my-posh config dsc set --state '{\n  \"states\": [\n    {\"source\":\"~/work.omp.json\",\"format\":\"json\"},\n    {\"source\":\"~/personal.omp.json\",\"format\":\"json\"}\n  ]\n}'\n```\n\n### Shell-Specific Initialization\n\nInitialize multiple shells with different configuration:\n\n```bash\n# Bash with one configuration\noh-my-posh init bash dsc set --state '{\"states\":[{\"name\":\"bash\",\"command\":\"oh-my-posh init bash --config ~/bash-theme.omp.json\"}]}'\n\n# PowerShell with another configuration\noh-my-posh init pwsh dsc set --state '{\"states\":[{\"name\":\"pwsh\",\"command\":\"oh-my-posh init pwsh --config ~/pwsh-theme.omp.json\"}]}'\n```\n\n## Supported shells\n\nDSC shell configuration supports the following shells:\n\n- **bash**: Configures `.bashrc` or `.bash_profile`\n- **zsh**: Configures `.zshrc`\n- **fish**: Configures `~/.config/fish/config.fish`\n- **pwsh**: Configures PowerShell profile (`$PROFILE`)\n- **nu**: Configures `~/.config/nushell/config.nu`\n- **elvish**: Configures `.elvish/rc.elv`\n- **xonsh**: Configures `.xonshrc`\n\nThe shell integration automatically:\n\n- Creates configuration files if they don't exist\n- Updates existing Oh My Posh initialization commands\n- Preserves shell-specific command syntax\n- Maintains proper whitespace and formatting\n\n## See Also\n\n- [General configuration](/docs/configuration/general) - Main configuration documentation\n- [Installation](/docs/installation/windows) - Installing Oh My Posh\n- [Themes](https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes) - Available themes\n- [WinGet configuration](https://learn.microsoft.com/windows/package-manager/configuration/) - WinGet DSC documentation\n- [Microsoft DSC](https://learn.microsoft.com/powershell/dsc/overview) - Microsoft DSC documentation\n"
  },
  {
    "path": "website/docs/experimental/streaming.mdx",
    "content": "---\nid: streaming\ntitle: Streaming (Beta)\nsidebar_label: Streaming\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n:::warning Experimental Feature\nStreaming is an **experimental beta feature** that is currently under active development. The behavior and configuration\nmay change in future releases. Use with caution in production environments.\n:::\n\n## What is Streaming?\n\nStreaming is a new rendering mode for Oh My Posh that displays your prompt progressively as segments complete their execution.\nInstead of waiting for all segments to finish before showing the prompt, streaming mode shows an initial prompt immediately\nand updates it incrementally as data becomes available.\n\n## How Does It Work?\n\nIn the traditional rendering mode, Oh My Posh:\n\n1. Executes all segments (some may take time to fetch data from APIs, run commands, etc.)\n2. Waits for all segments to complete\n3. Renders the complete prompt once\n4. Displays the result\n\nWith **streaming mode**, Oh My Posh:\n\n1. Immediately displays a prompt with fast segments\n2. Shows `...` for segments that are still loading (override using the segment's `placeholder` property)\n3. Progressively updates the prompt as slow segments complete\n4. Re-renders the prompt with updated data\n\nThis provides a more responsive experience, especially when you have segments that fetch remote data or perform\ntime-consuming operations.\n\n## Enabling Streaming\n\nTo enable streaming mode, add the `streaming` property to your configuration file and set it to a positive integer representing the timeout in milliseconds for pending segments. For example:\n\n<Config\n  data={{\n    streaming: 100,\n  }}\n/>\n\n:::warning\nSetting a very low timeout (e.g., 0 or 50ms) may cause visual glitches depending on the shell's rendering capabilities.\nWe recommend starting with a timeout of around 100ms and adjusting based on your experience.\n:::\n\n## Shell Support\n\nStreaming mode is currently supported in:\n\n- **PowerShell** (version 7.2+)\n- **Zsh**\n- **Fish**\n\nSupport for additional shells may be added in future releases.\n\n## Feedback\n\nIf you encounter issues or have suggestions for the streaming feature, please open an issue on the\n[Oh My Posh GitHub repository][issues].\n\n[issues]: https://github.com/JanDeDobbeleer/oh-my-posh/issues\n"
  },
  {
    "path": "website/docs/faq.mdx",
    "content": "---\nid: faq\ntitle: FAQ\nsidebar_label: 🤔 FAQ\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport Config from \"@site/src/components/Config.js\";\n\nBefore validating anything, make sure you're on the [latest version][latest] of Oh My Posh and your terminal and shell are up-to-date.\n\n## My prompt is broken after upgrading to PowerShell 7.4\n\nPowerShell 7.4 has an [issue][pwsh-20733] in encoding which affects the rendering of Oh My Posh.\nYou can work around this by forcing the entire shell to UTF8.\n\n```powershell\n[Console]::OutputEncoding = [Text.Encoding]::UTF8\noh-my-posh init pwsh --config ~/custom.omp.json | Invoke-Expression\n```\n\n:::warning\nForcing the entire session to UTF8 can have unwanted side effects for other executables. We can't be held liable for that,\nconsider this a temporary workaround until the original PowerShell [issue][pwsh-20733] is resolved.\n:::\n\n## I want to disable the upgrade notice\n\nYou can disable the upgrade notice using the following command once:\n\n```bash\noh-my-posh disable notice\n```\n\nIf you want to enable it again, run:\n\n```bash\noh-my-posh enable notice\n```\n\n## The prompt is slow (delay in showing the prompt between commands)\n\n:::tip Windows\nThe delay you're experiencing may be linked to the real-time protection features of antivirus software.\n\nTo potentially alleviate this delay, ensure that Windows Defender or your primary antivirus software has an [exclusion][exclusion] set for the full path of the executable. To identify the full path of the executable in question, you can run the following command in a PowerShell prompt:\n\n```powershell\n(Get-Command oh-my-posh).Source\n```\n\nAdditionally, check your antivirus settings for features that actively scan scripts during execution. Even with exclusions set, some antivirus programs might still actively scan scripts, which can introduce a noticeable delay.\n:::\n\n:::caution\nAlways proceed with caution to maintain a balance between system performance and security. Modifying security settings or adding exclusions can expose your system to potential threats.\n:::\n\n<Tabs\n  queryString=\"shell\"\n  defaultValue=\"powershell\"\n  groupId=\"shell\"\n  values={[\n    { label: 'powershell', value: 'powershell', },\n    { label: 'others', value: 'others', },\n  ]\n}>\n<TabItem value=\"powershell\">\n\nYou can use the `oh-my-posh debug` functionality to see where Oh My Posh spends its time.\nIn case there's no clear culprit (timings indicate everything's OK), chances are some modules are the culprit.\nWe bootstrap a few PowerShell modules to maximize compatibility, but sometimes these can introduce unwanted side-effects.\n\nThe modules we support are:\n\n- posh-git\n\n</TabItem>\n<TabItem value=\"others\">\n\nYou can use Oh My Posh's built-in debug functionality to identify slow segments.\n\n```bash\noh-my-posh debug\n```\n\nWhenever there's a segment that spikes, see if there might be updates to the underlying functionality (usually shell commands).\n\n</TabItem>\n</Tabs>\n\nIf only your Git repo paths are slow, then try running [`git gc`][git-gc] to clean up and optimize the local repository.\n\nIf nothing seems to resolve the issue, feel free to [create an issue][new-issue].\n\n## There are rectangles instead of icons in my prompt\n\nThe font you're using doesn't have the needed standard extended glyph set like [Nerd Font][nf] does.\nWindows Terminal ships with Cascadia Code by default which has a powerline patched variant called Cascadia Code PL,\nbut also that one misses certain interesting icons. You can fall back to any theme with the `.minimal` indication,\nor make use of a Nerd Font. Have a look at the [font][font] section for more context in case you're using all the right conditions.\n\n## Text decoration styles like bold and dimmed don't work\n\nThe text decoration styles are based on your terminal emulator's capabilities.\n\nA quick way to check if your terminal supports a specific style escape sequence is to take a look at the `terminfo` database, on Linux.\nRefer [this page on ArchWiki][arch-terminfo].\n\nIf you are on Windows, use Windows Terminal. It closely copies the `xterm-256color` capabilities.\nSee the [PowerShell docs on terminal support][ps-ansi-docs] and [this GitHub comment][xterm-gh-comment].\n\n## Windows Terminal: Unexpected space between segments/text\n\nWindows Terminal has some issues with [rendering certain glyphs][wt-glyph]. These issues are on [their backlog][wt-glyphs].\nA temporary workaround is to use an invisible character at the end (`\\u2800`), or a zero width character (`\\u200a`) before the icon.\n\nIn case you didn't export the config yet (it's the default, or you're using the `--config` flag with a predefined theme), you can follow\nthe steps [here][export] to export it to a local file so you can adjust the [segment's][segment] `template`.\n\nIn the example below, it's assumed that the execution segment's icon `\\ueba2` has an unexpected space after it in Windows Terminal.\n\n<Config\n  data={{\n    type: \"executiontime\",\n    template: \"\\ueba2\", // unexpected space\n  }}\n/>\n\nAdjust it by adding `\\u2800` immediately after the icon.\n\n<Config\n  data={{\n    type: \"executiontime\",\n    template: \"\\ueba2\\u2800\", // solved\n  }}\n/>\n\n## Jetbrains terminals: Icons do not render\n\nThey need to work on their terminal, somehow it only supports UTF-8 and not UTF-16.\n[An issue][jb-icons] is available for a follow-up here.\n\n## Strange colouring after exiting VIM or when using the PowerShell progress bootstrap\n\nThis bug is caused by Windows Terminal and/or VIM. There are two issues for this, one at [Windows Terminal][wt-vim] and\none at [VIM][vim-wt].\n\n## Conda: environment name displayed in front of the prompt\n\nConda will automatically prepend the prompt with the name of the environment you're in.\nTo solely rely on Oh My Posh to set the prompt, you can configure the following setting to hide it.\nMake sure to add this **before** initializing Oh My Posh.\n\n```bash\nconda config --set changeps1 False\n```\n\n## Python venv: Prompt changes on activating virtual environment\n\nVirtual environments created with `venv` add the active environment's name to the prompt automatically.\nTo disable this behaviour, set `VIRTUAL_ENV_DISABLE_PROMPT` environment variable to `1` on your system. Example files:\n\nNote: Tilde (~) in paths refers to your user's home directory.\n\n<Tabs\n  queryString=\"shell\"\n  defaultValue=\"powershell\"\n  groupId=\"shell\"\n  values={[\n    { label: 'powershell', value: 'powershell', },\n    { label: 'fish', value: 'fish', },\n    { label: 'others', value: 'others', },\n  ]\n}>\n<TabItem value=\"powershell\">\n\n```powershell\n# Your PowerShell $PROFILE\n$env:VIRTUAL_ENV_DISABLE_PROMPT=1\n```\n\n</TabItem>\n<TabItem value=\"fish\">\n\n```fish\n# ~/.config/fish/config.fish\nset -x VIRTUAL_ENV_DISABLE_PROMPT 1\n```\n\n</TabItem>\n<TabItem value=\"others\">\n\n```bash\n# ~/.bashrc (bash) or ~/.zprofile or ~/.zshrc (zsh)\nexport VIRTUAL_ENV_DISABLE_PROMPT=1\n```\n\n</TabItem>\n</Tabs>\n\n## PowerShell: The term 'Set-Theme' is not recognized as the name of a cmdlet, function, script file, or operable program.\n\nYou need to migrate using the following [guide][migrating].\n\n## PowerShell: Running in ConstrainedLanguage mode\n\nYou're here because you've seen the following message:\n\n```powershell\n[WARNING] ConstrainedLanguage mode detected, unable to set console to UTF-8.\nWhen using PowerShell in ConstrainedLanguage mode, please set the\nconsole mode manually to UTF-8. See here for more information:\nhttps://ohmyposh.dev/docs/faq#powershell-running-in-constrainedlanguage-mode\n```\n\nWhen running PowerShell in ConstrainedLanguage mode, we can't set the console to UTF-8. This will cause the prompt to be rendered incorrectly.\nThere's a few [options][utf-8] to set the console to UTF-8 from an OS perspective on Windows, other systems shouldn't be impacted.\n\nTo remove the message after manual configuration, you can add the following to your `$PROFILE` before importing Oh My Posh:\n\n```powershell\n$env:POSH_CONSTRAINED_LANGUAGE = 1\n```\n\n## PowerShell: The term '.../oh-my-posh.exe' is not recognized as a name of a cmdlet...\n\nFor example:\n\n```\n&: The term 'C:/Users/TommiGr├╢nlund/.oh-my-posh/oh-my-posh.exe' is not recognized as a name of a cmdlet, function, script file, or executable program.\nCheck the spelling of the name, or if a path was included, verify that the path is correct and try again.\n```\n\nThe issue is that PowerShell on Windows doesn't yet default to UTF-8. Resolve the issue by setting the shell to UTF-8 in the scope of initializing Oh My Posh.\n\n:::info Why it matters?\nIf the location contains non-ASCII characters, non-UTF-8 PowerShell may provide a wrong path to Oh My Posh, which can break the initialization.\n\nThe scenario for non-ASCII location:\n\n- Your computer has a non-ASCII username.\n- Your [config file](./installation/customize.mdx) is under your `$HOME`.\n  :::\n\nTo do so, edit your `$PROFILE`, find the line that initializes Oh My Posh (as highlighted below), and change it to the following:\n\n```powershell\n$previousOutputEncoding = [Console]::OutputEncoding\n[Console]::OutputEncoding = [Text.Encoding]::UTF8\ntry {\n    // highlight-start\n    oh-my-posh init pwsh --config ~/custom.omp.json | Invoke-Expression\n    // highlight-end\n} finally {\n    [Console]::OutputEncoding = $previousOutputEncoding\n}\n```\n\nAlternatively, let the whole shell become UTF-8. (Be aware: Unwanted side effects can happen.) Add the following line to the top of your `$PROFILE`:\n\n```powershell\n$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding\n```\n\n## Zsh: No command history (Ctrl+R does not work)\n\nThis issue occurs when you're using plain zsh in combination with Oh My Posh.\nYou can fix this by adding the right configuration to `~/.zshrc`.\n\n```bash\nHISTFILE=~/.zsh_history\nHISTSIZE=10000\nSAVEHIST=10000\nsetopt appendhistory\n```\n\n## ZSH: No such shell function 'zle-line-init'\n\nThis is most likely caused by two Oh My Posh init lines in your `.zshrc`, remove one of them. See [here][zsh-init].\n\n## Fish: Display current bind (Vim) mode\n\nBy default, Oh My Posh will not re-render the prompt (i.e., generate a new prompt) until a new command is run, so you should\nexport `$fish_bind_mode` to `FISH__BIND_MODE` and call the `omp_repaint_prompt` function to do prompt re-rendering when\n`$fish_bind_mode` changes:\n\n```fish\nfunction rerender_on_bind_mode_change --on-variable fish_bind_mode\n    if test \"$fish_bind_mode\" != paste -a \"$fish_bind_mode\" != \"$FISH__BIND_MODE\"\n        set -gx FISH__BIND_MODE $fish_bind_mode\n        omp_repaint_prompt\n    end\nend\n```\n\nNext, mask the `fish_default_mode_prompt` function to prevent it from echoing the current mode:\n\n```fish\nfunction fish_default_mode_prompt --description \"Display vi prompt mode\"\n    # This function is masked and does nothing\nend\n```\n\nAfter that, you can use the value in a template. The following replicates the [example in the Fish documentation][fish-mode-prompt]:\n\n<Config\n  data={{\n    type: \"text\",\n    template:\n      '{{ if eq .Env.FISH__BIND_MODE \"default\" }}<red>[N]</>{{ else if eq .Env.FISH__BIND_MODE \"insert\" }}<green>[I]</>{{ else if eq .Env.FISH__BIND_MODE \"replace_one\" }}<green>[R]</>{{ else if eq .Env.FISH__BIND_MODE \"visual\"}}<brmagenta>[V]</>{{ else }}<red>[?]</>{{ end }}',\n  }}\n/>\n\n## Fish: Integrate with `Alt+←` and `Alt+→` Bindings to `prevd` and `nextd`\n\nFish supports using `Alt+←` (Alt+Left) and `Alt+→` (Alt+Right) bindings to [navigate the directory history](https://fishshell.com/docs/current/interactive.html#id13).\n\nTo have oh-my-posh update the directory context as the directory history is navigated, use a function that calls `omp_repaint_prompt` when the `$PWD` variable changes:\n\n```fish\nfunction rerender_on_dir_change --on-variable PWD\n  omp_repaint_prompt\nend\n```\n\n## After updating my Nerd Font to a newer version, the prompt displays unknown characters\n\nNerd Fonts moved the icons to a different location in the font for v3.\nThis can cause the prompt to display unknown characters. There's a built-in migration in Oh My Posh to fix this.\n\nTo migrate, run the following command:\n\n```bash\noh-my-posh config migrate glyphs --write\n```\n\nThis will update your configuration file to use the new glyph locations. Do know they might look different, as they also\nupdated the icons themselves. A backup of the current config can be found in the same location with a `.bak` extension.\n\n## Xonsh: Right prompt jumps to bottom of the screen\n\nThis is a known problem with Xonsh. The issue is tracked [here][xonsh-issue].\n\n[pwsh-20733]: https://github.com/PowerShell/PowerShell/issues/20733\n[exclusion]: https://support.microsoft.com/en-us/windows/add-an-exclusion-to-windows-security-811816c0-4dfd-af4a-47e4-c301afe13b26\n[arch-terminfo]: https://wiki.archlinux.org/title/Bash/Prompt_customization#Terminfo_escape_sequences\n[ps-ansi-docs]: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_ansi_terminals?view=powershell-7.2\n[xterm-gh-comment]: https://github.com/microsoft/terminal/issues/6045#issuecomment-631743728\n[git-gc]: https://git-scm.com/docs/git-gc\n[new-issue]: https://github.com/JanDeDobbeleer/oh-my-posh/issues/new/choose\n[latest]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest\n[wt-glyph]: https://github.com/microsoft/terminal/issues/3546\n[wt-glyphs]: https://github.com/microsoft/terminal/issues?q=is%3Aissue+is%3Aopen+unicode+width\n[export]: installation/customize.mdx#custom-configuration\n[segment]: configuration/segment.mdx\n[nf]: https://www.nerdfonts.com/\n[font]: /docs/installation/fonts\n[jb-icons]: https://youtrack.jetbrains.com/issue/IDEA-248010\n[migrating]: /docs/migrating\n[wt-vim]: https://github.com/microsoft/terminal/issues/3794\n[vim-wt]: https://github.com/vim/vim/issues/5092\n[utf-8]: https://github.com/PowerShell/PowerShell/issues/7233#issuecomment-640243647\n[xonsh-issue]: https://github.com/xonsh/xonsh/issues/3810\n[zsh-init]: https://github.com/JanDeDobbeleer/oh-my-posh/discussions/3462#discussioncomment-5155790\n[fish-mode-prompt]: https://fishshell.com/docs/current/cmds/fish_mode_prompt.html#example\n"
  },
  {
    "path": "website/docs/installation/customize.mdx",
    "content": "---\nid: customize\ntitle: Customize\nsidebar_label: 🧩 Customize\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\nThe standard initialization sets Oh My Posh' default, built-in theme.\n\nTo set a new configuration or theme you need to change the `--config` option of the `oh-my-posh init <shell>`\nline in your `profile` or `.<shell>rc` script (see [prompt][prompt]).\n\nThese are the three possible values the `--config` flag can handle:\n\n- a path to a local configuration file\n\n  ```powershell\n  --config 'C:/Users/Posh/myconfig.omp.json'\n  ```\n\n- a pointer to a theme, without the extensions\n\n  ```powershell\n  --config 'jandedobbeleer'\n  ```\n\n- a URL pointing to a remote config\n\n  ```powershell\n  --config 'https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/jandedobbeleer.omp.json'\n  ```\n\n:::info\nUsing a theme name (like `jandedobbeleer`) or a remote URL requires an active internet connection\nand will download the configuration on shell start. Caching is in place, but for better performance,\nit's recommended to use a local configuration file.\n:::\n\n## Set the configuration\n\nThe example below uses a local path to the [jandedobbeleer][jandedobbeleer] theme, adjust the `--config` value\nto reflect your configuration file, local or remote.\n\n<Tabs\n  queryString=\"shell\"\n  defaultValue=\"powershell\"\n  groupId=\"shell\"\n  values={[\n    { label: 'bash', value: 'bash', },\n    { label: 'cmd', value: 'cmd', },\n    { label: 'elvish', value: 'elvish', },\n    { label: 'fish', value: 'fish', },\n    { label: 'nu', value: 'nu', },\n    { label: 'powershell', value: 'powershell', },\n    { label: 'xonsh', value: 'xonsh', },\n    { label: 'zsh', value: 'zsh', },\n  ]\n}>\n<TabItem value=\"bash\">\n\n:::caution Git bash\nUse the full path to the config file, not the relative path or `~` as a shorthand for `$HOME`.\n:::\n\nAdjust the Oh My Posh init line in `~/.bashrc` (could be `~/.profile` or `~/.bash_profile` depending\non your environment) by adding the `--config` flag with the location of your configuration.\n\n```bash\neval \"$(oh-my-posh init bash --config ~/jandedobbeleer.omp.json)\"\n```\n\nOnce altered, reload your profile for the changes to take effect.\n\n```bash\nexec bash\n```\n\n</TabItem>\n<TabItem value=\"cmd\">\n\nAdjust the Oh My Posh init line in `oh-my-posh.lua` by adding the `--config` flag with the location\nof your configuration.\n\n```lua title=\"oh-my-posh.lua\"\nload(io.popen('oh-my-posh init cmd --config C:/Users/Posh/jandedobbeleer.omp.json'):read(\"*a\"))()\n```\n\n:::caution\nUse the full path to the config file, not the relative path. You can make use of **forward slashes** to\navoid having to use double backslashes.\n:::\n\nOnce altered, restart cmd for the changes to take effect.\n\n</TabItem>\n<TabItem value=\"elvish\">\n\nAdjust the Oh My Posh init line in `~/.elvish/rc.elv` by adding the `--config` flag with the location\nof your configuration.\n\n```bash\neval (oh-my-posh init elvish --config ~/jandedobbeleer.omp.json)\n```\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec elvish\n```\n\n</TabItem>\n<TabItem value=\"fish\">\n\n:::caution\nIt is recommended to use the latest version of Fish. Versions below 4.1.0 have issues and do not support [transient prompt].\n:::\n\nAdjust the Oh My Posh init line in `~/.config/fish/config.fish` by adding the `--config` flag with\nthe location of your configuration.\n\n```bash\noh-my-posh init fish --config ~/jandedobbeleer.omp.json | source\n```\n\nOnce altered, reload your config for the changes to take effect.\n\n```bash\n. ~/.config/fish/config.fish\n```\n\n</TabItem>\n<TabItem value=\"nu\">\n\n:::caution\nOh My Posh requires Nushell `v0.104.0` or higher.\n:::\n\nAdjust the Oh My Posh init line in the Nushell config file (`$nu.config-path`) by adding the `--config` flag\nwith the location of your configuration.\n\n```bash\noh-my-posh init nu --config ~/jandedobbeleer.omp.json\n```\n\n</TabItem>\n<TabItem value=\"powershell\">\n\nAdjust the Oh My Posh init line in your `$PROFILE` by adding the `--config` flag with the location\nof your configuration.\n\n```powershell\noh-my-posh init pwsh --config ~/jandedobbeleer.omp.json | Invoke-Expression\n```\n\nOnce altered, reload your profile for the changes to take effect.\n\n```powershell\n. $PROFILE\n```\n\n:::info\nWhen the above command gives an error, make sure to create the profile first and add the `oh-my-posh init` above.\n\n```powershell\nNew-Item -Path $PROFILE -Type File -Force\n```\n\nIn this scenario, it can also be that PowerShell blocks running local scripts. To solve that, set PowerShell\nto only require remote scripts to be signed using `Set-ExecutionPolicy RemoteSigned`, or [sign the profile][sign].\n:::\n\n</TabItem>\n<TabItem value=\"xonsh\">\n\nAdjust the Oh My Posh init line in `~/.xonshrc` by adding the `--config` flag with the location of your configuration.\n\n```bash\nexecx($(oh-my-posh init xonsh --config ~/jandedobbeleer.omp.json))\n```\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec xonsh\n```\n\n</TabItem>\n<TabItem value=\"zsh\">\n\nAdjust the Oh My Posh init line in `~/.zshrc` by adding the `--config` flag with the location of your configuration.\n\n```bash\neval \"$(oh-my-posh init zsh --config ~/jandedobbeleer.omp.json)\"\n```\n\nOnce altered, reload your profile for the changes to take effect.\n\n```bash\nexec zsh\n```\n\n</TabItem>\n</Tabs>\n\n:::tip wsl\nWhen using oh-my-posh in Windows and the WSL, know that you can **share your theme with the WSL** by pointing to a theme in your\nWindows user's home folder.\n\nInside the WSL, you can find your Windows user's home folder here: `/mnt/c/Users/<WINDOWSUSERNAME>`.\n:::\n\n## Custom configuration\n\nMaybe there's a theme you like, but you don't fancy the colors. Or, maybe there's a segment you\nwant to tweak/add, or replace some of the icons with a different one. Whatever the case, **read through\navailable options first**, by starting with the [configuration][configuration].\n\nYou can export the current theme (default, or set via `--config`) to the format you like (`json`, `yaml`, or `toml`)\nwhich can be used to tweak and store as your own custom configuration.\n\n```bash\noh-my-posh config export --config jandedobbeleer --output ~/.mytheme.omp.json\n```\n\n## Live reloading\n\nBy default, the configuration is cached for performance reasons. If you make changes to your configuration file\nand want to see those changes reflected in your prompt without restarting your shell, you can use the following\ncommand to enable live reload.\n\n```bash\noh-my-posh enable reload\n```\n\nYou can disable live reload with:\n\n```bash\noh-my-posh disable reload\n```\n\n### Previewing changes\n\nIf you want to preview your changes, you can use the following command to render every configured prompt.\n\n```bash\noh-my-posh print preview\n```\n\nUse the `--force` flag in case you want to render all segments, regardless of the current context.\n\n```bash\noh-my-posh print preview --force\n```\n\n## Read the docs\n\nTo fully understand how to customize a theme, read through the documentation in the configuration and segments sections.\nThe [configuration][configuration] section covers the basic building blocks and concepts of Oh My Posh themes, while the\nsegments section covers how to configure each available segment.\n\n[configuration]: configuration/general.mdx\n[prompt]: prompt.mdx\n[jandedobbeleer]: /docs/themes#jandedobbeleer\n[sign]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_signing?view=powershell-7.5#methods-of-signing-scripts\n[transient prompt]: /docs/configuration/transient\n"
  },
  {
    "path": "website/docs/installation/fonts.mdx",
    "content": "---\nid: fonts\ntitle: Fonts\nsidebar_label: 🔤 Fonts\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\n## Nerd Fonts\n\nOh My Posh was designed to use [Nerd Fonts][nerdfonts]. Nerd Fonts are popular fonts that are patched to include icons.\nTo see the icons displayed in Oh My Posh, **install** a [Nerd Font][nerdfonts], and **configure** your terminal to use it.\n\n:::info\nFonts need to be installed on the host system as this is a UI setting, not a command line, or shell configuration.\nThis means **when running inside a container or WSL**, you need to install the font on the host system and configure\nyour terminal emulator to use it.\n:::\n\n## Installation\n\n<Tabs\n    defaultValue=\"oh-my-posh\"\n    values={[\n        { label: 'Oh My Posh', value: 'oh-my-posh' },\n        { label: 'Homebrew', value: 'homebrew' },\n        { label: 'PowerShell', value: 'powershell' }\n    ]\n}>\n<TabItem value=\"oh-my-posh\">\n\nOh My Posh has a CLI to help you select and install a [Nerd Font][nerdfonts]:\n\n:::info\nWhen running as root/administrator, the fonts will be installed system-wide.\nWhen running as a regular user, the fonts will be installed in the user's font directory.\nBy default, Oh My Posh installs the `.ttf` version of the font in case multiple versions are available.\n:::\n\n```bash\noh-my-posh font install\n```\n\nThis will present a list of Nerd Font libraries, from which you can  select `Meslo`, which includes the\n`Meslo LGM NF` font we recommend. Note that you can also install it directly via:\n\n```bash\noh-my-posh font install meslo\n```\n\n</TabItem>\n<TabItem value=\"homebrew\">\n\nIf you're using Homebrew, you can search for and install Nerd Fonts directly:\n\n```bash\nbrew search nerd-font\n\nbrew install --cask font-fira-code-nerd-font\n```\n\n</TabItem>\n<TabItem value=\"powershell\">\n\nIf you're using PowerShell, you can use the [NerdFonts][nerdfonts-ps] module to install Nerd Fonts:\n\n```powershell\nInstall-PSResource -Name NerdFonts\nImport-Module -Name NerdFonts\n\nInstall-NerdFont -Name FiraCode   # Tab completion works on name\n```\n\nTo install for all users, elevated permissions are required:\n\n```powershell\nInstall-NerdFont -Name FiraCode -Scope AllUsers\n```\n\n</TabItem>\n</Tabs>\n\n## Configuration\n\nMake sure to **configure your terminal** to use the font you have installed. The following sections will show you how to do this for the most popular terminals.\n\n<Tabs\n    defaultValue=\"wt\"\n    values={[\n        { label: 'Windows Terminal', value: 'wt' },\n        { label: 'Visual Studio Code', value: 'code' },\n        { label: 'Visual Studio', value: 'vs' },\n        { label: 'Apple Terminal', value: 'apple' }\n    ]\n}>\n<TabItem value=\"wt\">\n\nOnce you have installed a Nerd Font, you will need to configure the Windows Terminal to use it. This can be easily done\nby modifying the Windows Terminal settings (default shortcut: `CTRL + SHIFT + ,`). In your `settings.json` file, add the\n`font.face` attribute under the `defaults` attribute in `profiles`:\n\n```json\n{\n    \"profiles\":\n    {\n        \"defaults\":\n        {\n            \"font\":\n            {\n                \"face\": \"MesloLGM Nerd Font\"\n            }\n        }\n    }\n}\n```\n\n</TabItem>\n<TabItem value=\"code\">\n\nWhen using Visual Studio Code, you will need to configure the integrated Terminal to make use of the Nerd Font as well. This can be done by changing the `Integrated: Font Family` value in the Terminal settings (default shortcut: `CTRL + ,` and search for `Integrated: Font Family` or via `Users` -> `Features` -> `Terminal`).\n\nIf you are using the JSON based settings, you will need to update the `terminal.integrated.fontFamily` value. Example in case of `MesloLGM Nerd Font` Nerd Font:\n\n```json\n\"terminal.integrated.fontFamily\": \"MesloLGM Nerd Font\"\n```\n\n</TabItem>\n<TabItem value=\"vs\">\n\nWhen using Visual Studio, you will need to configure the integrated Terminal to make use of the Nerd Font as well. This can be done by opening the settings\nin `Tools > Options > Environment > Fonts and Colors > Terminal` and selecting a font like `MesloLGM Nerd Font`.\n\n:::warning\nOTF fonts do not appear in Visual Studio's Terminal settings, only TTF fonts. See [here][vs-otf] for more information.\n:::\n\n</TabItem>\n<TabItem value=\"apple\">\n\nWhen using Apple Terminal, you will need to configure the settings based on the profile you are using. This can be done by opening the settings in `Profiles > Select the appropriate profile from the left panel > Text > Font` and select a font like `MesloLGM Nerd Font`.\n\nThis can also be configured via a terminal command. Example in case of `MesloLGM Nerd Font Mono` Nerd Font on the Basic profile for Apple Terminal:\n\n```bash\nosascript -e 'tell application \"Terminal\" to set font of settings set \"Basic\" to \"MesloLGL Nerd Font Mono\"'\n```\n:::warning\nThe command has only been tested on macOS Sequoia 15.5 24F74.\n:::\n</TabItem>\n</Tabs>\n\n## Other Fonts\n\nIf you are not interested in using a Nerd Font, you will want to use a theme which doesn't include any Nerd Font icons.\nThe `minimal` themes do not make use of Nerd Font icons.\n\n[Creating your own theme][configuration] is always an option too 😊\n\n[nerdfonts]: https://www.nerdfonts.com/\n[nerdfonts-ps]: https://psmodule.io/NerdFonts\n[configuration]: /docs/installation/customize\n[vs-otf]: https://stackoverflow.com/questions/75252606/is-it-possible-to-use-nerd-fonts-as-the-font-for-terminals-in-visual-studio\n"
  },
  {
    "path": "website/docs/installation/homebrew.md",
    "content": "<!-- markdownlint-disable-next-line MD041 -->\nA [Homebrew][brew] Formula and Cask are available for easy installation.\n\n```bash\nbrew install jandedobbeleer/oh-my-posh/oh-my-posh\n```\n\nUpdating is done via:\n\n```bash\nbrew update && brew upgrade oh-my-posh\n```\n\n:::tip\nIn case you see [strange behaviour][strange] in your shell, reload it after upgrading Oh My Posh.\nFor example in zsh:\n\n```bash\nbrew update && brew upgrade && exec zsh\n```\n\n:::\n\n[brew]: https://brew.sh\n[strange]: https://github.com/JanDeDobbeleer/oh-my-posh/issues/1287\n"
  },
  {
    "path": "website/docs/installation/linux.mdx",
    "content": "---\nid: linux\ntitle: Linux\nsidebar_label: 🐧 Linux\n---\n\nimport Next from \"./next.md\";\n\n## Set up your terminal\n\nOh My Posh uses ANSI color codes under the hood, these should work in every terminal,\nbut you may have to set the environment variable `$TERM` to `xterm-256color` for it to work.\n\n:::info\nTo display all icons, we recommend the use of a [Nerd Font][fonts].\n:::\n\n## Installation\n\n:::info\nBefore running the below commands, make sure that you have updated `curl` and the\nclient certificate store on the target machine.\n\nThe installation script requires the following tools to be installed:\n\n- `curl`\n- `unzip`\n- `realpath`\n- `dirname`\n\n:::\n\nInstall the latest version for your system by running the following command:\n\n```bash\ncurl -s https://ohmyposh.dev/install.sh | bash -s\n```\n\nBy default the script will install to `~/bin` or `~/.local/bin` depending on which one exists,\nor the existing Oh My Posh executable's installation folder.\nIf you want to install to a different location you can specify it using the `-d` flag:\n\n```bash\ncurl -s https://ohmyposh.dev/install.sh | bash -s -- -d ~/bin\n```\n\n<Next />\n\n[fonts]: /docs/installation/fonts\n"
  },
  {
    "path": "website/docs/installation/macos.mdx",
    "content": "---\nid: macos\ntitle: macOS\nsidebar_label: 🍏 macOS\n---\n\nimport InstallHomebrew from \"./homebrew.md\";\nimport Next from \"./next.md\";\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\n## Set up your terminal\n\nAs the standard terminal only supports [256 colors][256-colors], we advise using\n[iTerm2][iterm2] or any other modern day macOS terminal that supports ANSI characters.\n\n:::info\nTo display all icons, we recommend the use of a [Nerd Font][fonts].\n:::\n\n## Installation\n\n<Tabs\n  defaultValue=\"homebrew\"\n  groupId=\"install\"\n  values={[\n    { label: 'Homebrew', value: 'homebrew', },\n    { label: 'MacPorts', value: 'macports', }\n  ]\n}>\n<TabItem value=\"homebrew\">\n\n<InstallHomebrew />\n\n</TabItem>\n<TabItem value=\"macports\">\n\nYou can install Oh My Posh via [MacPorts] which is maintained by the [community][ports page].\n\n```bash\nsudo port selfupdate\nsudo port install oh-my-posh\n```\n\nOh My Posh will be installed at `/opt/local/bin/oh-my-posh`.\n\nUpdating is done via:\n\n```bash\nsudo port selfupdate\nsudo port upgrade oh-my-posh\n```\n\nMore details on the [ports page] for Oh My Posh.\n\n</TabItem>\n</Tabs>\n\n## Troubleshooting\n\n:::tip\nIf you see an error that says, \"[conditional binary operator expected][outdated-bash]\" you probably need to update to a newer version of bash.\n\n```bash\nbrew install bash\ngrep -qxF \"$(brew --prefix)/bin/bash\" /etc/shells || sudo bash -c 'echo \"$(brew --prefix)/bin/bash\" >> /etc/shells'\nchsh -s \"$(brew --prefix)/bin/bash\" $USER\n```\n:::\n\n<Next />\n\n[256-colors]: /docs/configuration/colors#standard-colors\n[iterm2]: https://iterm2.com\n[fonts]: /docs/installation/fonts\n[MacPorts]: https://www.macports.org\n[ports page]: https://ports.macports.org/port/oh-my-posh/\n[outdated-bash]: https://github.com/JanDeDobbeleer/oh-my-posh/discussions/3429\n"
  },
  {
    "path": "website/docs/installation/next.md",
    "content": "<!-- markdownlint-disable-next-line MD041 -->\n## Next\n\nNow that Oh My Posh is installed, you can go ahead and configure your terminal and shell to\nget the prompt to look exactly like you want.\n\n- install a [font][fonts]\n- configure your terminal/editor to use the installed font\n- configure your shell to [use Oh My Posh][prompt]\n- (optional) configure a theme or [custom prompt configuration][customize]\n\n[fonts]: fonts.mdx\n[prompt]: prompt.mdx\n[customize]: customize.mdx\n"
  },
  {
    "path": "website/docs/installation/prompt.mdx",
    "content": "---\nid: prompt\ntitle: Change your prompt\nsidebar_label: ✨ Prompt\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\n\n:::tip\nIf you have no idea which shell you're currently using, Oh My Posh has a utility switch that can tell that to you.\n:::\n\n```bash\noh-my-posh get shell\n```\n\n<Tabs\n  queryString=\"shell\"\n  defaultValue=\"powershell\"\n  groupId=\"shell\"\n  values={[\n    { label: 'bash', value: 'bash', },\n    { label: 'claude', value: 'claude', },\n    { label: 'cmd', value: 'cmd', },\n    { label: 'elvish', value: 'elvish', },\n    { label: 'fish', value: 'fish', },\n    { label: 'nu', value: 'nu', },\n    { label: 'powershell', value: 'powershell', },\n    { label: 'xonsh', value: 'xonsh', },\n    { label: 'zsh', value: 'zsh', },\n  ]\n}>\n<TabItem value=\"bash\">\n\nAdd the following snippet as the last line to `~/.bashrc` (could be `~/.profile` or `~/.bash_profile` depending on your environment):\n\n```bash\neval \"$(oh-my-posh init bash)\"\n```\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec bash\n```\n\nOr, when using `~/.profile`.\n\n```bash\n. ~/.profile\n```\n\n</TabItem>\n<TabItem value=\"claude\">\n\nTo enable Claude Code integration with Oh My Posh, configure Claude Code to use Oh My Posh as the statusline command.\n\nAdd the following to your Claude Code settings:\n\n```json title=\"~/.claude/settings.json\"\n{\n  \"statusLine\": {\n    \"type\": \"command\",\n    \"command\": \"oh-my-posh claude\",\n    \"padding\": 0\n  }\n}\n```\n\nFor more information about the Claude segment properties and customization options, see the [Claude segment documentation](/docs/segments/cli/claude).\n\n</TabItem>\n<TabItem value=\"cmd\">\n\nThere's no out-of-the-box support for Windows CMD when it comes to custom prompts.\nThere is however a way to do it using [Clink][clink], which at the same time supercharges\nyour cmd experience. Follow the installation instructions and make sure you select autostart.\n\nIntegrating Oh My Posh with Clink is easy: create a new file called oh-my-posh.lua in your Clink\nscripts directory (run `clink info` inside cmd to find that file's location).\n\n```lua title=\"oh-my-posh.lua\"\nload(io.popen('oh-my-posh init cmd'):read(\"*a\"))()\n```\n\nOnce added, restart cmd for the changes to take effect.\n\n:::info\nClink has builtin support for Oh My Posh. It allows you to set the prompt using the `clink` command.\n\n```bash\nclink config prompt use oh-my-posh\n```\n\nTo set the configuration file, use the following command:\n\n```bash\nclink set ohmyposh.theme <path>\n```\n:::\n\n</TabItem>\n<TabItem value=\"elvish\">\n\nAdd the following snippet as the last line to `~/.elvish/rc.elv`:\n\n```bash\neval (oh-my-posh init elvish)\n```\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec elvish\n```\n\n</TabItem>\n<TabItem value=\"fish\">\n\n:::caution\nIt is recommended to use the latest version of Fish. Versions below 4.1.0 have issues and do not support [transient prompt].\n:::\n\nAdd the following snippet as the last line to `~/.config/fish/config.fish`:\n\n```bash\noh-my-posh init fish | source\n```\n\nOnce added, reload your config for the changes to take effect.\n\n```bash\nexec fish\n```\n\n</TabItem>\n<TabItem value=\"nu\">\n\n:::caution\nOh My Posh requires Nushell `v0.104.0` or higher.\n:::\n\nAdd the following snippet as the last line to the Nushell config file (`$nu.config-path`):\n\n```bash\noh-my-posh init nu\n```\n\nOnce added, restart Nushell for the changes to take effect.\n\n</TabItem>\n<TabItem value=\"powershell\">\n\nEdit your PowerShell profile script, you can find its location under the `$PROFILE` variable in your preferred PowerShell version. For example, using notepad:\n\n```powershell\nnotepad $PROFILE\n```\n\n:::info\nWhen the above command gives an error, make sure to create the profile first.\n\n```powershell\nNew-Item -Path $PROFILE -Type File -Force\n```\n\nIn this scenario, it can also be that PowerShell blocks running local scripts. To solve that, set PowerShell\nto only require remote scripts to be signed using `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine`, or [sign the profile][sign].\n:::\n\nAdd the following snippet as the last line to your PowerShell profile script:\n\n```powershell\noh-my-posh init pwsh | Invoke-Expression\n```\n\n:::tip Execution policy\nIn case the execution policy disables executing unsigned scripts on your system, you can fallback to evaluating\nthe script instead. Use the `--eval` flag to do so:\n\n```powershell\noh-my-posh init pwsh --eval | Invoke-Expression\n```\n\nBe aware this will make initializing the shell slower.\n:::\n\nOnce added, reload your profile for the changes to take effect.\n\n```powershell\n. $PROFILE\n```\n\n</TabItem>\n<TabItem value=\"xonsh\">\n\nAdd the following snippet as the last line to `~/.xonshrc`:\n\n```bash\nexecx($(oh-my-posh init xonsh))\n```\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec xonsh\n```\n\n</TabItem>\n<TabItem value=\"zsh\">\n\nAdd the following snippet as the last line to `~/.zshrc`:\n\n```bash\neval \"$(oh-my-posh init zsh)\"\n```\n\n:::tip\nAs the standard terminal has issues displaying the ANSI characters correctly, you might want to skip loading just for that terminal and instead of the line above, place this in your `~/.zshrc`:\n\n```bash\nif [ \"$TERM_PROGRAM\" != \"Apple_Terminal\" ]; then\n  eval \"$(oh-my-posh init zsh)\"\nfi\n```\n\nNote this will still load Oh My Posh for [iTerm2][iterm2] or any other modern day macOS terminal that supports ANSI characters.\n:::\n\nOnce added, reload your profile for the changes to take effect.\n\n```bash\nexec zsh\n```\n\n</TabItem>\n</Tabs>\n\n[clink]: https://chrisant996.github.io/clink/\n[iterm2]: https://iterm2.com/\n[sign]: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_signing?view=powershell-7.3#methods-of-signing-scripts\n[transient prompt]: /docs/configuration/transient\n"
  },
  {
    "path": "website/docs/installation/upgrade.mdx",
    "content": "---\nid: upgrade\ntitle: Upgrade\nsidebar_label: ♻️ Upgrade\n---\n\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport Config from \"@site/src/components/Config.js\";\n\n## Configuration\n\nOh My Posh can display the availability of an update, or auto update itself when\nenabled by adding the following to your configuration.\n\n<Config\n  data={{\n    upgrade: {\n      notice: true,\n      interval: \"168h\",\n      auto: false,\n      source: \"cdn\",\n    },\n  }}\n/>\n\n:::info\nAuto upgrade will never upgrade major versions. This is to avoid introducing breaking changes\nwithout explicit user acknowledgement.\n:::\n\n:::warning\nUpgrade features are never enabled when you have `async` loading enabled in your configuration\nand the shell you're using supports it.\n:::\n\n| Name       |   Type    | Default | Description                                                                                                                                                                                                                |\n| ---------- | :-------: | :-----: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `notice`   | `boolean` | `false` | enable displaying the upgrade notice on shell start, only checks based on `interval`                                                                                                                                       |\n| `auto`     | `boolean` | `false` | automatically update Oh My Posh when an update is found, only checks based on `interval`                                                                                                                                   |\n| `interval` | `string`  |  `24h`  | the duration for which not to check for an update. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library                                      |\n| `source`   | `string`  |  `cdn`  | where to fetch the information from. Accepted values are `cdn` (`https://cdn.ohmyposh.dev/releases/latest/version.txt`) and `github` (`https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest/download/version.txt`) |\n\n## Upgrade\n\n### Manual\n\nWhile you can always follow the upgrade steps listed under the installation section,\nyou can also use the `upgrade` command to update Oh My Posh to the latest version.\n\n```powershell\noh-my-posh upgrade\n```\n\n### Automated\n\n<Tabs\n  defaultValue=\"cli\"\n  groupId=\"sample\"\n  values={[\n    { label: 'CLI', value: 'cli', },\n    { label: 'Configuration', value: 'config', },\n  ]\n}>\n<TabItem value=\"cli\">\n\n```powershell\noh-my-posh enable upgrade\n```\n\n</TabItem>\n<TabItem value=\"config\">\n\n<Config\n  data={{\n    upgrade: {\n      interval: \"168h\",\n      auto: true,\n      source: \"cdn\",\n    },\n  }}\n/>\n\n</TabItem>\n</Tabs>\n\n[customize]: /docs/installation/customize#custom-configuration\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/installation/windows.mdx",
    "content": "---\nid: windows\ntitle: Windows\nsidebar_label: 🪟 Windows\n---\n\nimport ThemedImage from '@theme/ThemedImage';\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport Next from \"./next.md\";\n\n## Set up your terminal\n\nWhile Oh My Posh works on the standard terminal, we advise using the [Windows Terminal][wt].\n\n:::info\nTo display all icons, we recommend the use of a [Nerd Font][fonts].\n:::\n\n:::caution\nWhen using oh-my-posh inside the WSL, make sure to follow the [Linux][linux] installation guide.\n:::\n\n<a href=\"https://apps.microsoft.com/detail/xp8k0hkjfrxgck?mode=mini\" target=\"_blank\">\n  <ThemedImage\n    alt=\"msstore\"\n    width=\"232\"\n    height=\"68\"\n    sources={{\n      light: '/img/msstore-dark.svg',\n      dark: '/img/msstore-light.svg',\n    }}\n  />\n</a>\n\n## Installation\n\n<Tabs\n  defaultValue=\"winget\"\n  groupId=\"install\"\n  values={[\n    { label: 'winget', value: 'winget', },\n    { label: 'manual', value: 'manual', },\n    { label: 'chocolatey', value: 'chocolatey'},\n  ]\n}>\n<TabItem value=\"winget\">\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nwinget install JanDeDobbeleer.OhMyPosh --source winget\n```\n\n</TabItem>\n<TabItem value=\"manual\">\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nSet-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://ohmyposh.dev/install.ps1'))\n```\n\n</TabItem>\n<TabItem value=\"chocolatey\">\n\n:::info\nThe chocolatey package is maintained by the community and might not be up to date.\nIn case of issues, please contact the [maintainer][choco-maintainer].\n:::\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nchoco install oh-my-posh\n```\n\n</TabItem>\n</Tabs>\n\n<Next />\n\n## Update\n\n<Tabs\n  defaultValue=\"winget\"\n  groupId=\"install\"\n  values={[\n    { label: 'winget', value: 'winget', },\n    { label: 'manual', value: 'manual', },\n    { label: 'chocolatey', value: 'chocolatey'},\n  ]\n}>\n<TabItem value=\"winget\">\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nwinget upgrade JanDeDobbeleer.OhMyPosh --source winget\n```\n\n</TabItem>\n<TabItem value=\"manual\">\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nSet-ExecutionPolicy Bypass -Scope Process -Force; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://ohmyposh.dev/install.ps1'))\n```\n\n</TabItem>\n<TabItem value=\"chocolatey\">\n\n:::info\nThe chocolatey package is maintained by the community and might not be up to date.\nIn case of issues, please contact the [maintainer][choco-maintainer].\n:::\n\nOpen a PowerShell prompt and run the following command:\n\n```powershell\nchoco upgrade oh-my-posh\n```\n\n</TabItem>\n</Tabs>\n\n[fonts]: /docs/installation/fonts\n[wt]: https://github.com/microsoft/terminal\n[linux]: /docs/installation/linux\n[choco-maintainer]: https://github.com/digitalcoyote/chocolatey-packages\n"
  },
  {
    "path": "website/docs/migrating-module.md",
    "content": "---\nid: migrating\ntitle: PowerShell module\nsidebar_label: ⚰️ PowerShell Module\n---\n\n## Problem statement\n\nTraditionally, the module was the only way to install oh-my-posh using `Install-Module oh-my-posh`.\nToday, with the shift to the executable version over a year ago, it only acts as a wrapper around the\nexecutable, offering no additional functionality. Throughout the year, the following changes have been made:\n\n- don't ship all binaries in the Module but download on `Import-Module`\n- move all functionality from the Module to the [init][init] script\n\nThere's a problem with the Module due to the following:\n\n- downloading the binary is a problem on company managed computers\n- the module syncs cross device thanks to OneDrive sync, causing versions to be out of sync and [configs to break][idiots]\n- it's impactful having to explain the difference time and time again (for me)\n\n## Migration steps\n\n### Remove the module's cached files\n\n```powershell\nRemove-Item $env:POSH_PATH -Force -Recurse\n```\n\n:::warning\nIf you added custom elements to this location, they will be deleted with the command above.\nMake sure to move these before running the command.\n:::\n\n### Install oh-my-posh\n\nSee your platform's installation guide. The preferred ways are **winget** and **Homebrew**.\n\n- [Windows][windows]\n- [macOS][macos]\n- [Linux][linux]\n\n### Uninstall the PowerShell module\n\n```powershell\nUninstall-Module oh-my-posh -AllVersions\n```\n\nDelete the import of the PowerShell module in your `$PROFILE`\n\n```powershell\nImport-Module oh-my-posh\n```\n\n### Adjust setting the prompt\n\nIf you're still using `Set-PoshPrompt`, replace that statement with the following:\n\n#### I have a custom theme\n\n```powershell\noh-my-posh init pwsh --config ~/.custom.omp.json | Invoke-Expression\n```\n\nAnd replace `~/.custom.omp.json` with the location of your theme.\n\n#### I have an out-of-the-box theme\n\n```powershell\noh-my-posh init pwsh --config \"jandedobbeleer\" | Invoke-Expression\n```\n\nReplace `jandedobbeleer` with the theme you use.\n\n[init]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/src/shell/scripts/omp.ps1\n[idiots]: https://ohmyposh.dev/blog/idiots-everywhere\n[windows]: /docs/installation/windows\n[macos]: /docs/installation/macos\n[linux]: /docs/installation/linux\n"
  },
  {
    "path": "website/docs/segments/cli/angular.mdx",
    "content": "---\nid: angular\ntitle: Angular\nsidebar_label: Angular\n---\n\n## What\n\nDisplay the currently active [Angular CLI][angular-cli-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"angular\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#1976d2\",\n    template: \" \\uE753 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |    Default     | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |     `true`     | fetch the angular version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |     `none`     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `angular.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |   `angular`    | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[angular-cli-docs]: https://angular.io/cli\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/argocd.mdx",
    "content": "---\nid: argocd\ntitle: ArgoCD Context\nsidebar_label: ArgoCD\n---\n\n## What\n\nDisplay the current [ArgoCD][argocd] context name, user and/or server.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"argocd\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FFA400\",\n    template: \" \\ue734 {{ .Name }}:{{ .User }}@{{ .Server }} \",\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Name }}\n```\n\n:::\n\n### Properties\n\n| Name      | Type     | Description                       |\n| --------- | -------- | --------------------------------- |\n| `.Name`   | `string` | the current context name          |\n| `.Server` | `string` | the server of the current context |\n| `.User`   | `string` | the user of the current context   |\n\n[argocd]: https://argo-cd.readthedocs.io/en/stable/\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/cli/aurelia.mdx",
    "content": "---\nid: aurelia\ntitle: Aurelia\nsidebar_label: Aurelia\n---\n\n## What\n\nDisplay the currently active [Aurelia][aurelia] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"aurelia\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#de1f84\",\n    template: \" \\u03b1 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |    Default     | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |     `true`     | fetch the aurelia version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |     `none`     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `package.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |   `aurelia`    | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[aurelia]: https://docs.aurelia.io/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/bazel.mdx",
    "content": "---\nid: bazel\ntitle: Bazel\nsidebar_label: Bazel\n---\n\n## What\n\nDisplay the currently active [Bazel][bazel-github] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"bazel\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#43a047\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                           Default                           | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                           `false`                           | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                           `true`                            | display the Bazel version - defaults to                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |                           `none`                            | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                             | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                          `context`                          | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                             | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info documentation                                                                                                                  |\n| `icon`                 |  `string`  |                          `\\ue63a`                           | the icon for the segment                                                                                                                                                                                                             |\n| `extensions`           | `[]string` | `*.bazel, *.bzl, BUILD, WORKSPACE, .bazelrc, .bazelversion` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |            `bazel-bin, bazel-out, bazel-testlogs`           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                           `bazel`                           | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Icon }} {{ .Error }}{{ else }}{{ url .Icon .URL }} {{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n| `.Icon`  | `string` | the icon representing Bazel's logo                 |\n\n[bazel-github]: https://github.com/bazelbuild/bazel\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/buf.mdx",
    "content": "---\nid: buf\ntitle: Buf\nsidebar_label: Buf\n---\n\n## What\n\nDisplay the currently active [Buf CLI][buf-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"buf\",\n    style: \"plain\",\n    foreground: \"#1000D6\",\n    template: \" 🐃 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                 Default                 | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                 `false`                 | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                 `true`                  | fetch the active version or not; useful if all you need is an icon indicating `buf`                                                                                                                                                  |\n| `cache_duration`       |  `string`  |                 `none`                  | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                         | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                `context`                | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                         | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `buf.yaml, buf.gen.yaml, buf.work.yaml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                         | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                  `buf`                  | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[buf-docs]: https://buf.build/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/bun.mdx",
    "content": "---\nid: bun\ntitle: Bun\nsidebar_label: Bun\n---\n\n## What\n\nDisplay the currently active [Bun CLI][bun-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"bun\",\n    style: \"plain\",\n    foreground: \"#3C82F6\",\n    template: \" \\ue76f {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |        Default        | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |        `false`        | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |         `true`        | fetch the active version or not; useful if all you need is an icon indicating `bun`                                                                                                                                                  |\n| `cache_duration`       |  `string`  |         `none`        | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                       | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |       `context`       | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                       | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `bun.lockb, bun.lock` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                       | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |         `bun`         | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[bun-docs]: https://bun.com/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/claude.mdx",
    "content": "---\nid: claude\ntitle: Claude Code\nsidebar_label: Claude Code\n---\n\n## What\n\nDisplay Claude Code session information including the current AI model, token usage, costs, and workspace details.\nShows a visual gauge of context window usage and formatted cost/token information for monitoring your Claude usage.\n\nThis segment integrates with [Claude Code's statusline functionality][claude-docs]\nto provide real-time session data in your prompt.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"claude\",\n    style: \"diamond\",\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\ue0b4\",\n    foreground: \"#FFFFFF\",\n    background: \"#FF6B35\",\n    template:\n      \" \\udb82\\udfc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.Gauge }} \",\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\udb82\\udfc9 {{ .Model.DisplayName }} \\uf2d0 {{ .TokenUsagePercent.Gauge }}\n```\n\n:::\n\n### Properties\n\n| Name                 | Type            | Description                                        |\n| -------------------- | --------------- | -------------------------------------------------- |\n| `.SessionID`         | `string`        | Unique identifier for the Claude session           |\n| `.Model`             | `Model`         | AI model information                               |\n| `.Workspace`         | `Workspace`     | Workspace directory information                    |\n| `.Cost`              | `Cost`          | Cost and duration information                      |\n| `.ContextWindow`     | `ContextWindow` | Token usage information                            |\n| `.TokenUsagePercent` | `Percentage`    | Percentage of context window used (0-100)          |\n| `.FormattedCost`     | `string`        | Formatted cost string (e.g., \"$0.15\" or \"$0.0012\") |\n| `.FormattedTokens`   | `string`        | Human-readable token count (e.g., \"1.2K\", \"15.3M\") |\n\n#### Model Properties\n\n| Name           | Type     | Description                                           |\n| -------------- | -------- | ----------------------------------------------------- |\n| `.ID`          | `string` | Technical model identifier                            |\n| `.DisplayName` | `string` | Human-readable model name (e.g., \"Claude 3.5 Sonnet\") |\n\n#### Workspace Properties\n\n| Name          | Type     | Description               |\n| ------------- | -------- | ------------------------- |\n| `.CurrentDir` | `string` | Current working directory |\n| `.ProjectDir` | `string` | Root project directory    |\n\n#### Cost Properties\n\n| Name               | Type      | Description                            |\n| ------------------ | --------- | -------------------------------------- |\n| `.TotalCostUSD`    | `float64` | Total cost in USD                      |\n| `.TotalDurationMS` | `int64`   | Total session duration in milliseconds |\n\n#### ContextWindow Properties\n\n| Name                 | Type           | Description                                  |\n| -------------------- | -------------- | -------------------------------------------- |\n| `.TotalInputTokens`  | `int`          | Total input tokens used in the session       |\n| `.TotalOutputTokens` | `int`          | Total output tokens generated in the session |\n| `.ContextWindowSize` | `int`          | Maximum context window size for the model    |\n| `.CurrentUsage`      | `CurrentUsage` | Current message token usage                  |\n\n#### CurrentUsage Properties\n\n| Name            | Type  | Description                           |\n| --------------- | ----- | ------------------------------------- |\n| `.InputTokens`  | `int` | Input tokens for the current message  |\n| `.OutputTokens` | `int` | Output tokens for the current message |\n\n### Percentage Methods\n\nThe `TokenUsagePercent` property is a `Percentage` type that provides additional functionality:\n\n| Method       | Returns  | Description                                                        |\n| ------------ | -------- | ------------------------------------------------------------------ |\n| `.Gauge`     | `string` | Visual gauge showing remaining capacity using 5 bar blocks (▰▰▰▰▱) |\n| `.GaugeUsed` | `string` | Visual gauge showing used capacity using 5 bar blocks (▰▱▱▱▱)      |\n| `.String`    | `string` | Numeric percentage value (e.g., \"75\" for use in templates)         |\n\n## How it works\n\nThe segment reads session information from the `POSH_CLAUDE_STATUS` environment variable, which is automatically set when using the `oh-my-posh claude` command. The data includes:\n\n- Current AI model information\n- Token usage and context window utilization\n- Session costs and duration\n- Workspace directory information\n\nThe segment only displays when Claude Code is actively providing session data.\n\n[claude-docs]: https://code.claude.com/docs/en/statusline\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/cli/cmake.mdx",
    "content": "---\nid: cmake\ntitle: Cmake\nsidebar_label: Cmake\n---\n\n## What\n\nDisplay the currently active [Cmake][cmake-github] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"cmake\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#E8EAEE\",\n    background: \"#1E9748\",\n    template: \" \\ue794 cmake {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |          Default          | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |          `false`          | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |          `true`           | display the cmake version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |          `none`           | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |         `context`         | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.cmake, CMakeLists.txt` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |          `cmake`          | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[cmake-github]: https://github.com/Kitware/CMake\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/copilot.mdx",
    "content": "---\nid: copilot\ntitle: GitHub Copilot\nsidebar_label: GitHub Copilot\n---\n\n## What\n\nDisplay your [GitHub Copilot][copilot] usage statistics and quota information including premium interactions, inline completions, and chat usage.\nThis segment was inspired by [Elio Struyf's GitHub Copilot Usage Tauri application][tauri].\n\n## Authentication\n\nThis segment requires authentication with GitHub to access Copilot usage data. Use the built-in OAuth device code flow:\n\n```bash\noh-my-posh auth copilot\n```\n\nThis will:\n\n1. Display a device code and verification URL\n2. Open your browser to GitHub's authorization page\n3. Prompt you to enter the device code\n4. Store the access token securely for future use\n\nThe token is stored securely and will be used automatically by the segment.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"copilot\",\n    style: \"diamond\",\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\ue0b4\",\n    foreground: \"#111111\",\n    background: \"#fee898\",\n    template: \" \\uec1e {{ .Premium.Percent.Gauge }} \",\n    cache: {\n      duration: \"5m\",\n      strategy: \"session\",\n    },\n    options: {\n      http_timeout: 1000,\n    },\n  }}\n/>\n\n## Options\n\n| Name           | Type  | Default | Description                                           |\n| -------------- | ----- | ------- | ----------------------------------------------------- |\n| `http_timeout` | `int` | `20`    | The default timeout for HTTP requests in milliseconds |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\uec1e {{ .Premium.Percent.Gauge }}\n```\n\n:::\n\n### Properties\n\n| Name                 | Type           | Description                                   |\n| -------------------- | -------------- | --------------------------------------------- |\n| `.Premium`           | `CopilotUsage` | Premium interactions usage data               |\n| `.Premium.Used`      | `int`          | Number of premium interactions used           |\n| `.Premium.Limit`     | `int`          | Total premium interactions available          |\n| `.Premium.Percent`   | `Percentage`   | Percentage of premium quota used (0-100)      |\n| `.Premium.Remaining` | `Percentage`   | Percentage of premium quota remaining (0-100) |\n| `.Premium.Unlimited` | `bool`         | Whether premium quota is unlimited            |\n| `.Inline`            | `CopilotUsage` | Inline completions usage data                 |\n| `.Inline.Used`       | `int`          | Number of inline completions used             |\n| `.Inline.Limit`      | `int`          | Total inline completions available            |\n| `.Inline.Percent`    | `Percentage`   | Percentage of inline quota used (0-100)       |\n| `.Inline.Remaining`  | `Percentage`   | Percentage of inline quota remaining (0-100)  |\n| `.Inline.Unlimited`  | `bool`         | Whether inline quota is unlimited             |\n| `.Chat`              | `CopilotUsage` | Chat usage data                               |\n| `.Chat.Used`         | `int`          | Number of chat interactions used              |\n| `.Chat.Limit`        | `int`          | Total chat interactions available             |\n| `.Chat.Percent`      | `Percentage`   | Percentage of chat quota used (0-100)         |\n| `.Chat.Remaining`    | `Percentage`   | Percentage of chat quota remaining (0-100)    |\n| `.Chat.Unlimited`    | `bool`         | Whether chat quota is unlimited               |\n| `.BillingCycleEnd`   | `string`       | End date of current billing cycle             |\n\n### Percentage Methods\n\nThe `Percentage` type provides additional functionality beyond just the numeric value:\n\n| Method         | Returns  | Description                                                        |\n| -------------- | -------- | ------------------------------------------------------------------ |\n| `.Gauge()`     | `string` | Visual gauge showing remaining capacity using 5 bar blocks (▰▰▰▰▱) |\n| `.GaugeUsed()` | `string` | Visual gauge showing used capacity using 5 bar blocks (▰▱▱▱▱)      |\n| `.String()`    | `string` | Numeric percentage value (e.g., \"75\" for use in templates)         |\n\n**Example gauge visualization (shows remaining capacity):**\n\n- 0% used (100% remaining): `▰▰▰▰▰`\n- 20% used (80% remaining): `▰▰▰▰▱`\n- 40% used (60% remaining): `▰▰▰▱▱`\n- 60% used (40% remaining): `▰▰▱▱▱`\n- 80% used (20% remaining): `▰▱▱▱▱`\n- 100% used (0% remaining): `▱▱▱▱▱`\n\n**Example gaugeUsed visualization (shows used capacity):**\n\n- 0% used: `▱▱▱▱▱`\n- 20% used: `▰▱▱▱▱`\n- 40% used: `▰▰▱▱▱`\n- 60% used: `▰▰▰▱▱`\n- 80% used: `▰▰▰▰▱`\n- 100% used: `▰▰▰▰▰`\n\n**Example template with gauge:**\n\n```json\n\"template\": \"{{ .Premium.Percent.Gauge() }} {{ .Premium.Used }}/{{ .Premium.Limit }}\"\n```\n\n**Example template showing used capacity:**\n\n```json\n\"template\": \"{{ .Premium.Percent.GaugeUsed() }} {{ .Premium.Used }}/{{ .Premium.Limit }}\"\n```\n\n[copilot]: https://github.com/features/copilot\n[templates]: /docs/configuration/templates\n[tauri]: https://github.com/estruyf/github-copilot-usage-tauri\n"
  },
  {
    "path": "website/docs/segments/cli/deno.mdx",
    "content": "---\nid: deno\ntitle: Deno\nsidebar_label: Deno\n---\n\n## What\n\nDisplay the currently active [Deno CLI][deno-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"deno\",\n    style: \"plain\",\n    foreground: \"#3C82F6\",\n    template: \" \\ue7c0 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |         Default         | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |         `false`         | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |         `true`          | fetch the active version or not; useful if all you need is an icon indicating `deno`                                                                                                                                                 |\n| `cache_duration`       |  `string`  |         `none`          | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                         | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |        `context`        | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                         | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.ts, *.js, deno.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                         | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |         `deno`          | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[deno-docs]: https://deno.land/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/docker.mdx",
    "content": "---\nid: docker\ntitle: Docker\nsidebar_label: Docker\n---\n\n## What\n\nDisplay the current [Docker][docker] context. Will not be active when using the default context.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"docker\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#0B59E7\",\n    template: \" \\uf308 {{ .Context }} \",\n  }}\n/>\n\n## Options\n\n| Name            |    Type    |                                      Default                                     | Description                                                                                                                                                              |\n| --------------- | :--------: | :------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `display_mode`  |  `string`  |                                     `context`                                    | <ul><li>`files`: the segment is only displayed when a file `extensions` listed is present</li><li>`context`: displays the segment when a Docker context active</li></ul> |\n| `fetch_context` | `boolean`  |                                      `true`                                      | also fetch the current active Docker context when in the `files` display mode                                                                                            |\n| `extensions`    | `[]string` | `compose.yml, compose.yaml, docker-compose.yml, docker-compose.yaml, Dockerfile` | allows to override the default list of file extensions to validate                                                                                                       |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n\\uf308 {{ .Context }}\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description                |\n| ---------- | -------- | -------------------------- |\n| `.Context` | `string` | the current active context |\n\n[docker]: https://www.docker.com/\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/cli/firebase.mdx",
    "content": "---\nid: firebase\ntitle: Firebase\nsidebar_label: Firebase\n---\n\n## What\n\nDisplay the current active [Firebase][firebase] project.\n\nThis segment leverages the `firebase-tools.json` file generated by the [Firebase CLI][firebase-cli-docs].\nThe active files listed there are used to determine the current project against the current directory.\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"firebase\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#ffffff\",\n  \"background\": \"#FFA000\",\n  \"template\": \" \\udb82\\udd67 {{ .Project }}\"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Project }}\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description                                                              |\n| ---------- | -------- | ------------------------------------------------------------------------ |\n| `.Project` | `string` | the currently active project                                             |\n\n[templates]: /docs/configuration/templates\n[firebase]: https://firebase.google.com/\n[firebase-cli-docs]: https://firebase.google.com/docs/cli\n"
  },
  {
    "path": "website/docs/segments/cli/flutter.mdx",
    "content": "---\nid: flutter\ntitle: Flutter\nsidebar_label: Flutter\n---\n\n## What\n\nDisplay the currently active [flutter] version. Supports [fvm].\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"flutter\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#06A4CE\",\n    template: \" \\ue7dd {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                      Default                      | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                      `false`                      | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                      `true`                       | fetch the flutter version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |                      `none`                       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                     `context`                     | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.dart, pubspec.yaml, pubspec.yml, pubspec.lock` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                   `.dart_tool`                    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                   `fvm, flutter`                  | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[fvm]: https://fvm.app/\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[flutter]: https://flutter.dev/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/gitversion.mdx",
    "content": "---\nid: gitversion\ntitle: GitVersion\nsidebar_label: GitVersion\n---\n\n## What\n\nDisplay the [GitVersion][gitversion] version.\nWe _strongly_ recommend using [GitVersion Portable][gitversion-portable] for this.\n\n:::caution\nThe GitVersion CLI can be a bit slow, causing the prompt to feel slow. This is why we cache\nthe value for 30 minutes by default.\n:::\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"gitversion\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#ffffff\",\n  \"background\": \"#3a579b\",\n  \"template\": \" \\uF1D2 {{ .MajorMinorPatch }} \"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .MajorMinorPatch }}\n```\n\n:::\n\n### Properties\n\nYou can leverage all variables from the [GitVersion][gitversion] CLI. Have a look at their [documentation][docs] for more information.\n\n[gitversion]: https://github.com/GitTools/GitVersion\n[gitversion-portable]: http://chocolatey.org/packages/GitVersion.Portable\n[templates]: /docs/configuration/templates\n[docs]: https://gitversion.net/docs/reference/variables\n"
  },
  {
    "path": "website/docs/segments/cli/helm.mdx",
    "content": "---\nid: helm\ntitle: Helm\nsidebar_label: Helm\n---\n\n## What\n\nDisplay the version of [Helm][helm]\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"background\": \"#a7cae1\",\n  \"foreground\": \"#100e23\",\n  \"powerline_symbol\": \"\\ue0b0\",\n  \"template\": \" \\ue7fb {{ .Version }}\",\n  \"style\": \"powerline\",\n  \"type\": \"helm\"\n}}/>\n\n## Options\n\n| Name           | Type     | Default  | Description                                                                                                                                                      |\n| -------------- | :------: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `display_mode` | `string` | `always` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when a chart source file `Chart.yaml` (or `Chart.yml`) or helmfile `helmfile.yaml` (or `helmfile.yml`) is present </li></ul> |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n Helm {{ .Version }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type     | Description                |\n| ------------ | -------- | -------------------------- |\n| `.Version`   | `string` | Helm cli version           |\n\n[templates]: /docs/configuration/templates\n[helm]: https://helm.sh/\n"
  },
  {
    "path": "website/docs/segments/cli/kubectl.mdx",
    "content": "---\nid: kubectl\ntitle: Kubernetes\nsidebar_label: Kubernetes\n---\n\n## What\n\nDisplay the currently active [Kubernetes][kubernetes] context name and namespace name.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"kubectl\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#ebcc34\",\n    template: \" \\udb84\\udcfe {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}} \",\n    options: {\n      context_aliases: {\n        \"arn:aws:eks:eu-west-1:1234567890:cluster/posh\": \"posh\",\n      },\n      cluster_aliases: {\n        \"arn:aws:eks:eu-west-1:1234567890:cluster/posh\": \"posh-cluster\",\n      },\n    },\n  }}\n/>\n\n## Options\n\n| Name               |   Type    | Default | Description                                                                     |\n| ------------------ | :-------: | :-----: | ------------------------------------------------------------------------------- |\n| `display_error`    | `boolean` | `false` | show the error context when failing to retrieve the kubectl information         |\n| `parse_kubeconfig` | `boolean` | `true`  | parse kubeconfig files instead of calling out to kubectl to improve performance |\n| `context_aliases`  | `object`  |         | custom context namespace                                                        |\n| `cluster_aliases`  | `object`  |         | custom cluster name                                                             |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Context }}{{ if .Namespace }} :: {{ .Namespace }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type     | Description                           |\n| ------------ | -------- | ------------------------------------- |\n| `.Context`   | `string` | the current kubectl context           |\n| `.Namespace` | `string` | the current kubectl context namespace |\n| `.User`      | `string` | the current kubectl context user      |\n| `.Cluster`   | `string` | the current kubectl context cluster   |\n\n:::tip\n\nIt is common for the Kubernetes \"default\" namespace to be used when no namespace is provided. If you want your prompt to\nrender an empty current namespace using the word \"default\", you can use something like this for the template:\n\n```\n{{.Context}} :: {{if .Namespace}}{{.Namespace}}{{else}}default{{end}}\n```\n\n:::\n\n[templates]: /docs/configuration/templates\n[kubernetes]: https://kubernetes.io/\n"
  },
  {
    "path": "website/docs/segments/cli/mvn.mdx",
    "content": "---\nid: mvn\ntitle: Maven\nsidebar_label: Maven\n---\n\n## What\n\nDisplay the currently active [Maven][maven-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"mvn\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#FFFFFF\",\n    background: \"#2E2A65\",\n    template: \" \\ue82c {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |  Default  | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |  `false`  | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |  `true`   | fetch the Maven version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |  `none`   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  | `context` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `pom.xml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |   `mvn`   | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{.Full}}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[maven-docs]: https://maven.apache.org\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/nbgv.mdx",
    "content": "---\nid: nbgv\ntitle: Nerdbank.GitVersioning\nsidebar_label: Nbgv\n---\n\n## What\n\nDisplay the [Nerdbank.GitVersioning][nbgv] version.\n\n:::caution\nThe Nerdbank.GitVersioning CLI can be a bit slow causing the prompt to feel slow.\n:::\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"nbgv\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#ffffff\",\n  \"background\": \"#3a579a\",\n  \"template\": \" \\uF1D2 {{ .Version }} \"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Version }}\n```\n\n:::\n\n### Properties\n\n| Name                            | Type     | Description                                |\n| ------------------------------- | -------- | ------------------------------------------ |\n| `.Version`                      | `string` | the current version                        |\n| `.AssemblyVersion`              | `string` | the current assembly version               |\n| `.AssemblyInformationalVersion` | `string` | the current assembly informational version |\n| `.NuGetPackageVersion`          | `string` | the current nuget package version          |\n| `.ChocolateyPackageVersion`     | `string` | the current chocolatey package version     |\n| `.NpmPackageVersion`            | `string` | the current npm package version            |\n| `.SimpleVersion`                | `string` | the current simple version                 |\n\n[nbgv]: https://github.com/dotnet/Nerdbank.GitVersioning\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/cli/nix-shell.mdx",
    "content": "---\nid: nix-shell\ntitle: Nix Shell\nsidebar_label: Nix Shell\n---\n\n## What\n\nDisplays the [nix shell] status if inside a nix-shell environment.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"nix-shell\",\n    style: \"powerline\",\n    foreground: \"blue\",\n    background: \"transparent\",\n    template: \"(\\udb84\\udd05-{{ .Type }})\",\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\nvia {{ .Type }}-shell\"\n```\n\n:::\n\n### Properties\n\n| Name    | Type     | Description                                                 |\n| ------- | -------- | ----------------------------------------------------------- |\n| `.Type` | `string` | the type of nix shell, can be `pure`, `impure` or `unknown` |\n\n[nix shell]: https://nixos.org/guides/nix-pills/developing-with-nix-shell.html\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/cli/npm.mdx",
    "content": "---\nid: npm\ntitle: NPM\nsidebar_label: NPM\n---\n\n## What\n\nDisplay the currently active [npm][npm-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"npm\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    template: \"\\ue71e {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |              Default              | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |              `false`              | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |              `true`               | fetch the NPM version                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |              `none`               | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |             `context`             | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `package.json, package-lock.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                   | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |               `npm`               | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue71e {{.Full}}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[npm-docs]: https://docs.npmjs.com/about-npm\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/nx.mdx",
    "content": "---\nid: nx\ntitle: Nx\nsidebar_label: Nx\n---\n\n## What\n\nDisplay the currently active [Nx][nx-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"nx\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#1976d2\",\n    template: \" \\uE753 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |          Default          | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |          `false`          | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |          `true`           | fetch the active version or not                                                                                                                                                                                                      |\n| `cache_duration`       |  `string`  |          `none`           | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |         `context`         | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `workspace.json, nx.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |           `nx`            | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[nx-docs]: https://nx.dev\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/pnpm.mdx",
    "content": "---\nid: pnpm\ntitle: PNPM\nsidebar_label: PNPM\n---\n\n## What\n\nDisplay the currently active [pnpm][pnpm-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"pnpm\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#F9AD00\",\n    template: \" \\ue865 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |            Default             | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |            `false`             | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |             `true`             | fetch the PNPM version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |             `none`             | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |           `context`            | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `package.json, pnpm-lock.yaml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |             `pnpm`             | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue865 {{.Full}}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[pnpm-docs]: https://pnpm.io\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/quasar.mdx",
    "content": "---\nid: quasar\ntitle: Quasar\nsidebar_label: Quasar\n---\n\n## What\n\nDisplay the currently active [Quasar CLI][quasar-cli] version. Only rendered when the current or\nparent folder contains a `quasar.config` or `quasar.config.js` file.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"quasar\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#00B4FF\",\n    template:\n      \" \\ue87f {{.Full}}{{ if .HasVite }} \\ueb29 {{ .Vite.Version }}{{ end }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |              Default              | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |              `false`              | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `missing_command_text` |  `string`  |                                   | text to display when the command is missing                                                                                                                                                                                          |\n| `fetch_version`        | `boolean`  |              `true`               | fetch the NPM version                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |              `none`               | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `display_mode`         |  `string`  |             `context`             | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `fetch_dependencies`   | `boolean`  |              `false`              | fetch the version number of the `vite` and `@quasar/app-vite` dependencies if present                                                                                                                                                |\n| `extensions`           | `[]string` | `quasar.config, quasar.config.js` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                   | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |              `quasar`             | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue87f {{.Full}}{{ if .HasVite }} \\ueb29 {{ .Vite.Version }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name       | Type         | Description                                        |\n| ---------- | ------------ | -------------------------------------------------- |\n| `.Full`    | `string`     | the full version                                   |\n| `.Major`   | `string`     | major number                                       |\n| `.Minor`   | `string`     | minor number                                       |\n| `.Patch`   | `string`     | patch number                                       |\n| `.URL`     | `string`     | URL of the version info / release notes            |\n| `.Error`   | `string`     | error encountered when fetching the version string |\n| `.Vite`    | `Dependency` | the `vite` dependency, if found                    |\n| `.AppVite` | `Dependency` | the `@quasar/app-vite` dependency, if found        |\n\n#### Dependency\n\n| Name       | Type      | Description                   |\n| ---------- | --------- | ----------------------------- |\n| `.Version` | `string`  | the full version              |\n| `.Dev`     | `boolean` | development dependency or not |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[quasar-cli]: https://quasar.dev/start/quasar-cli\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/react.mdx",
    "content": "---\nid: react\ntitle: React\nsidebar_label: React\n---\n\n## What\n\nDisplay the currently active [React][react] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"react\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#81a1c1\",\n    template: \" \\uE7ba {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |    Default     | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |     `true`     | fetch the react version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |     `none`     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `package.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |    `react`     | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[react]: https://react.dev/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/svelte.mdx",
    "content": "---\nid: svelte\ntitle: Svelte\nsidebar_label: Svelte\n---\n\n## What\n\nDisplay the currently active [Svelte][svelte-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"svelte\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#1976d2\",\n    template: \" \\ue697 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |      Default       | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |      `false`       | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |       `true`       | fetch the svelte version                                                                                                                                                                                                             |\n| `cache_duration`       |  `string`  |       `none`       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                    | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |      `files`       | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                    | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `svelte.config.js` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |      `svelte`      | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[svelte-docs]: https://svelte.dev/docs/svelte/overview\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/talosctl.mdx",
    "content": "---\nid: talosctl\ntitle: Talosctl Context\nsidebar_label: Talosctl\n---\n\n## What\n\nDisplays the currently active [Talosctl][talosctl] context name.\n\nThis segment leverages the `.talos/config` file generated by the [Talosctl CLI][talosctl].\nThe CLI docs can be found by going to Documentation > Reference > CLI.\nFor example, [v1.7 CLI][CLI].\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"talosctl\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#FFFFFF\",\n  \"background\": \"#FF6C00\",\n  \"template\": \" \\udb84\\udcfe {{ .Context }}\"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Context }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type     | Description                           |\n| ------------ | -------- | ------------------------------------- |\n| `.Context`   | `string` | the current talosctl context           |\n\n\n[templates]: /docs/configuration/templates\n[talosctl]: https://www.talos.dev/\n[CLI]: https://www.talos.dev/v1.7/reference/cli/\n"
  },
  {
    "path": "website/docs/segments/cli/taskwarrior.mdx",
    "content": "---\nid: taskwarrior\ntitle: Taskwarrior\nsidebar_label: Taskwarrior\n---\n\n## What\n\nDisplay [Taskwarrior][taskwarrior] task data for configurable commands. Each named command runs\n`task` with the specified arguments and exposes the raw output in the template.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"taskwarrior\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    template: \" \\uf4a0 {{ range $k, $v := .Commands }}{{ $k }}:{{ $v }} {{ end }}\",\n    options: {\n      commands: {\n        due: \"+PENDING due.before:tomorrow count\",\n        scheduled: \"+PENDING scheduled.before:tomorrow count\",\n        waiting: \"+WAITING count\",\n        context: \"_get rc.context\",\n      },\n    },\n  }}\n/>\n\n## Options\n\n| Name       | Type                | Default   | Description                                                                    |\n| ---------- | :-----------------: | :-------: | ------------------------------------------------------------------------------ |\n| `command`  | `string`            | `task`    | the Taskwarrior executable to use                                              |\n| `commands` | `map[string]string` | see below | map of name to Taskwarrior arguments; the raw output is exposed in `.Commands` |\n\n### Default `commands` value\n\n```json\n{\n  \"due\": \"+PENDING due.before:tomorrow count\",\n  \"scheduled\": \"+PENDING scheduled.before:tomorrow count\",\n  \"waiting\": \"+WAITING count\",\n  \"context\": \"_get rc.context\"\n}\n```\n\nEach entry runs `task <arguments>` and stores the trimmed stdout as a string. Remove entries\nyou do not need to keep prompt rendering fast.\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ \"\\uf4a0\" }} {{ range $k, $v := .Commands }}{{ $k }}:{{ $v }} {{ end }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type                | Description                                                                          |\n| ------------ | ------------------- | ------------------------------------------------------------------------------------ |\n| `.Commands`  | `map[string]string` | raw command output keyed by name with the first letter uppercased (e.g. `\"Due\"`)     |\n\n### Examples\n\nAccess a specific command result directly:\n\n```template\n {{ \"\\uf4a0\" }} Due: {{ .Commands.Due }}\n```\n\nDisplay multiple results:\n\n```template\n {{ \"\\uf4a0\" }} Due: {{ .Commands.Due }} | Waiting: {{ .Commands.Waiting }}\n```\n\nInclude the active context alongside task counts:\n\n```template\n {{ \"\\uf4a0\" }} {{ .Commands.Context }} - Due: {{ .Commands.Due }} Scheduled: {{ .Commands.Scheduled }}\n```\n\n[templates]: /docs/configuration/templates\n[taskwarrior]: https://taskwarrior.org\n"
  },
  {
    "path": "website/docs/segments/cli/tauri.mdx",
    "content": "---\nid: tauri\ntitle: Tauri\nsidebar_label: Tauri\n---\n\n## What\n\nDisplay the currently active [Tauri][tauri-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"tauri\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#1976d2\",\n    template: \" \\ue8bb {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |      Default      | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |      `false`      | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |      `true`       | fetch the tauri version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |      `none`       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |      `files`      | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `tauri.conf.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |    `src-tauri`    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |      `tauri`      | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[tauri-docs]: https://tauri.app/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/terraform.mdx",
    "content": "---\nid: terraform\ntitle: Terraform Context\nsidebar_label: Terraform\n---\n\n## What\n\nDisplay the currently active [Terraform][terraform] Workspace name.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"terraform\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#ebcc34\",\n    template: \" \\ue69a {{.WorkspaceName}}\",\n  }}\n/>\n\n## Options\n\n| Name            |   Type    |   Default   | Description                                                                        |\n| --------------- | :-------: | :---------: | ---------------------------------------------------------------------------------- |\n| `fetch_version` | `boolean` |   `false`   | fetch the version information from `versions.tf`, `main.tf` or `terraform.tfstate` |\n| `command`       | `string`  | `terraform` | the command(s) to run, allows support for `tofu`                                   |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .WorkspaceName }}{{ if .Version }} {{ .Version }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                       |\n| ---------------- | -------- | ------------------------------------------------- |\n| `.WorkspaceName` | `string` | is the current workspace name                     |\n| `.Version`       | `string` | terraform version (set `fetch_version` to `true`) |\n\n[templates]: /docs/configuration/templates\n[terraform]: https://developer.hashicorp.com/terraform\n"
  },
  {
    "path": "website/docs/segments/cli/ui5tooling.mdx",
    "content": "---\nid: ui5tooling\ntitle: UI5 Tooling\nsidebar_label: UI5 Tooling\n---\n\n## What\n\nDisplay the active [UI5 tooling][ui5-homepage] version (global or local if present -\nsee [the documentation][ui5-version-help]).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"#f5a834\",\n    foreground: \"#100e23\",\n    powerline_symbol: \"\\ue0b0\",\n    template: \" \\uf0adui5 {{ .Full }} \",\n    style: \"powerline\",\n    type: \"ui5tooling\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |   Default    | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |   `false`    | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |    `true`    | fetch the ui5tooling version                                                                                                                                                                                                         |\n| `cache_duration`       |  `string`  |    `none`    | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |              | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |  `context`   | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |              | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*ui5*.y*ml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |              | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |    `ui5`     | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[ui5-homepage]: https://sap.github.io/ui5-tooling\n[ui5-version-help]: https://sap.github.io/ui5-tooling/pages/CLI/#ui5-versions\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/umbraco.mdx",
    "content": "---\nid: umbraco\ntitle: Umbraco\nsidebar_label: Umbraco\n---\n\n## What\n\nDisplay current [Umbraco] Version if found inside the current working directory.\nThe segment will only show based on the following logic\n\n* The current folder contains the folder named umbraco\n* Modern Umbraco (.NET Core)\n    * Check to see if current folder contains one or more .csproj files\n    * Open .csproj XML files and check to see if Umbraco is installed as a PackageReference\n    * Read the installed version\n* Legacy Umbraco (.NET Framework)\n    * Check to see if the current folder contains a web.config\n    * Open the XML and look for AppSettings keys\n    * If umbraco is installed it has a setting called umbraco.core.configurationstatus OR umbracoConfigurationStatus\n    * Read the value inside this AppSetting to get its version\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"umbraco\",\n  \"background\": \"#ffffff\",\n  \"foreground\": \"#d886f1\",\n  \"style\": \"diamond\",\n  \"leading_diamond\": \"\\ue0b6\",\n  \"trailing_diamond\": \"\\ue0b4\",\n  \"template\": \"\\udb81\\udd49 {{ .Version }}\",\n  \"background_templates\": [\n    \"{{ if (.Modern) }}#3544B1{{ end }}\",\n    \"{{ if not (.Modern) }}#F79C37{{ end }}\"\n  ]\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Version }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type      | Description                                                                                                         |\n| -------------- | --------- | ------------------------------------------------------------------------------------------------------------------- |\n| `.Modern`      | `boolean` | a boolean to determine if this is modern Umbraco V9+ using modern .NET or if it's legacy Umbraco using .NET Framework |\n| `.Version`     | `string`  | the version of umbraco found                                                                                       |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[Umbraco]: https://umbraco.com/\n"
  },
  {
    "path": "website/docs/segments/cli/unity.mdx",
    "content": "---\nid: unity\ntitle: Unity\nsidebar_label: Unity\n---\n\n## What\n\nDisplay the currently active [Unity][unity] and C# versions.\n\nThe Unity version is displayed regardless of whether or not the corresponding C# version can be found.\nThe C# version is determined by first checking a static table.\nIf the Unity version isn't found, a web request is made to [the Unity docs][unity-csharp-page] to\ntry extracting it from there. A web request only occurs the first time a given `major.minor`\nUnity version is encountered. Subsequent invocations return the cached C# version.\n\nC# version display is only supported from Unity 2017.1.\n\nUnity 2017.1 - 2019.1 support two C# versions, depending on which scripting runtime is selected in Player Settings.\nThis segment always chooses the higher version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"unity\",\n    style: \"powerline\",\n    powerline_symbol: \"\\ue0b0\",\n    foreground: \"#111111\",\n    background: \"#ffffff\",\n    options: {\n      http_timeout: 2000,\n    },\n  }}\n/>\n\n## Options\n\n| Name           | Type  | Default | Description                                    |\n| -------------- | :---: | :-----: | ---------------------------------------------- |\n| `http_timeout` | `int` | `2000`  | in milliseconds - the timeout for http request |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n\\ue721 {{ .UnityVersion }}{{ if .CSharpVersion }} {{ .CSharpVersion }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description       |\n| ---------------- | -------- | ----------------- |\n| `.UnityVersion`  | `string` | the Unity version |\n| `.CSharpVersion` | `string` | the C# version    |\n\n[unity]: https://unity.com/\n[templates]: /docs/configuration/templates\n[unity-csharp-page]: https://docs.unity3d.com/Manual/CSharpCompiler.html\n"
  },
  {
    "path": "website/docs/segments/cli/xmake.mdx",
    "content": "---\nid: xmake\ntitle: XMake\nsidebar_label: XMake\n---\n\n## What\n\nDisplay the currently active [Xmake][xmake] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"xmake\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#e0f2f1\",\n    background: \"#22a079\",\n    template: \" xmake v{{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |   Default   | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |   `false`   | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |   `true`    | fetch the xmake version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |   `none`    | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |             | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |  `context`  | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |             | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `xmake.lua` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |             | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |   `xmake`   | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([into][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: configuration/templates.mdx\n[xmake]: https://xmake.io/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cli/yarn.mdx",
    "content": "---\nid: yarn\ntitle: Yarn\nsidebar_label: Yarn\n---\n\n## What\n\nDisplay the currently active [yarn][yarn-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"yarn\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#FFFFFF\",\n    background: \"#2E2A65\",\n    template: \" \\ue6a7 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |          Default          | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |          `false`          | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |          `true`           | fetch the Yarn version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |          `none`           | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |         `context`         | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `package.json, yarn.lock` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |          `yarn`           | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue6a7 {{.Full}}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[yarn-docs]: https://yarnpkg.com\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cloud/aws.mdx",
    "content": "---\nid: aws\ntitle: AWS Context\nsidebar_label: AWS\n---\n\n## What\n\nDisplay the currently active [AWS][aws] profile and region.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"aws\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FFA400\",\n    template: \" \\uE7AD {{.Profile}}{{if .Region}}@{{.Region}}{{end}}\",\n  }}\n/>\n\n## Options\n\n| Name              | Type      | Default | Description                                  |\n| ----------------- | :-------: | :-----: | -------------------------------------------- |\n| `display_default` | `boolean` | `true`  | display the segment when default user or not |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name            | Type     | Description                                 |\n| --------------- | -------- | ------------------------------------------- |\n| `.Profile`      | `string` | the currently active profile                |\n| `.Region`       | `string` | the currently active region                 |\n| `.RegionAlias`  | `string` | short alias for the currently active region |\n\n[templates]: /docs/configuration/templates\n[aws]: https://aws.amazon.com/\n"
  },
  {
    "path": "website/docs/segments/cloud/az.mdx",
    "content": "---\nid: az\ntitle: Azure Subscription\nsidebar_label: Azure\n---\n\n## What\n\nDisplay the currently active [Azure][azure] subscription information.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"az\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#9ec3f0\",\n    template: \" \\uebd8 {{ .EnvironmentName }}\",\n    options: {\n      source: \"pwsh\",\n    },\n  }}\n/>\n\n## Options\n\n| Name     |   Type   |          Default           | Description                                                                                                                                                                                                                                                                                      |\n| -------- | :------: | :------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `source` | `string` | <code>cli&#124;pwsh</code> | sources to get subscription information from. Can be any of the following values, joined by <code>&#124;</code> to loop multiple sources for context. <ul><li>`cli`: fetch the information from the CLI config</li><li>`pwsh`: fetch the information from the PowerShell Module config</li></ul> |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Name }}\n```\n\n:::\n\n### Properties\n\n| Name                 | Type      | Description                                                    |\n| -------------------- | --------- | -------------------------------------------------------------- |\n| `.EnvironmentName`   | `string`  | Azure environment name                                         |\n| `.HomeTenantID`      | `string`  | home tenant id                                                 |\n| `.ID`                | `string`  | subscription id                                                |\n| `.IsDefault`         | `boolean` | is the default subscription or not                             |\n| `.Name`              | `string`  | subscription name                                              |\n| `.State`             | `string`  | subscription state                                             |\n| `.TenantID`          | `string`  | tenant id                                                      |\n| `.TenantDisplayName` | `string`  | tenant name                                                    |\n| `.User.Name`         | `string`  | user name                                                      |\n| `.User.Type`         | `string`  | user type                                                      |\n| `.Origin`            | `string`  | where we received the information from, can be `CLI` or `PWSH` |\n\n[templates]: /docs/configuration/templates\n[azure]: https://azure.microsoft.com\n[az]: https://www.powershellgallery.com/packages/Az\n"
  },
  {
    "path": "website/docs/segments/cloud/azd.mdx",
    "content": "---\nid: azd\ntitle: Azure Developer CLI\nsidebar_label: Azure Dev CLI\n---\n\n## What\n\nDisplay the currently active environment in the [Azure Developer CLI][azd].\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"azd\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#9ec3f0\",\n    template: \" \\uebd8 {{ .DefaultEnvironment }} \",\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\uebd8 {{ .DefaultEnvironment }}\n```\n\n:::\n\n### Properties\n\n| Name                  | Type     | Description                          |\n| --------------------- | -------- | ------------------------------------ |\n| `.DefaultEnvironment` | `string` | Azure Developer CLI environment name |\n| `.Version`            | `number` | Config version number                |\n\n[templates]: /docs/configuration/templates\n[azd]: https://aka.ms/azd\n"
  },
  {
    "path": "website/docs/segments/cloud/azfunc.mdx",
    "content": "---\nid: azfunc\ntitle: Azure Functions\nsidebar_label: Azure Functions\n---\n\n## What\n\nDisplay the currently active [Azure Functions CLI][az-func-core-tools] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"azfunc\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FEAC19\",\n    template: \" \\uf0e7 {{ .Full }} \",\n    options: {\n      fetch_version: true,\n      display_mode: \"files\",\n    },\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                     Default                     | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                     `false`                     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                     `true`                      | fetch the Azure Functions CLI version                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |                     `none`                      | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                 | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                    `context`                    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                 | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `host.json, local.settings.json, function.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                 | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                     `func`                      | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: configuration/templates.mdx\n[az-func-core-tools]: https://github.com/Azure/azure-functions-core-tools\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cloud/cds.mdx",
    "content": "---\nid: cds\ntitle: CDS (SAP CAP)\nsidebar_label: CDS\n---\n\n## What\n\nDisplay the active [CDS CLI][sap-cap-cds] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"#a7cae1\",\n    foreground: \"#100e23\",\n    powerline_symbol: \"\\ue0b0\",\n    template: \" \\ue311 cds {{ .Full }} \",\n    style: \"powerline\",\n    type: \"cds\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                  Default                  | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                  `false`                  | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                  `true`                   | fetch the CDS version                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |                  `none`                   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                           | text to display when the cds command is missing                                                                                                                                                                                      |\n| `display_mode`         |  `string`  |                 `context`                 | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `.cdsrc.json, .cdsrc-private.json, *.cds` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                   `cds`                   | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                        |\n| ---------------- | -------- | -------------------------------------------------- |\n| `.Full`          | `string` | the full version                                   |\n| `.Major`         | `string` | major number                                       |\n| `.Minor`         | `string` | minor number                                       |\n| `.Patch`         | `string` | patch number                                       |\n| `.Error`         | `string` | error encountered when fetching the version string |\n| `.HasDependency` | `bool`   | a flag if `@sap/cds` was found in `package.json`   |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: configuration/templates.mdx\n[sap-cap-cds]: https://cap.cloud.sap/docs/tools/#command-line-interface-cli\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cloud/cf.mdx",
    "content": "---\nid: cf\ntitle: Cloud Foundry\nsidebar_label: Cloud Foundry\n---\n\n## What\n\nDisplay the active [Cloud Foundry CLI][cloud-foundry] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"#a7cae1\",\n    foreground: \"#100e23\",\n    powerline_symbol: \"\\ue0b0\",\n    template: \" \\uf40a cf {{ .Full }} \",\n    style: \"powerline\",\n    type: \"cf\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |         Default          | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |         `false`          | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |          `true`          | display the Cloud Foundry CLI version                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |          `none`          | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                          | text to display when the java command is missing                                                                                                                                                                                     |\n| `display_mode`         |  `string`  |        `context`         | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                          | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `manifest.yml, mta.yaml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                          | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |           `cf`           | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[cloud-foundry]: https://github.com/cloudfoundry/cli\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/cloud/cftarget.mdx",
    "content": "---\nid: cftarget\ntitle: Cloud Foundry Target\nsidebar_label: Cloud Foundry Target\n---\n\n## What\n\nDisplay the details of the logged [Cloud Foundry endpoint][cf-target] (`cf target` details).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"#a7cae1\",\n    foreground: \"#100e23\",\n    powerline_symbol: \"\\ue0b0\",\n    template: \" \\uf40a {{ .Org }}/{{ .Space }} \",\n    style: \"powerline\",\n    type: \"cftarget\",\n  }}\n/>\n\n## Options\n\n| Name           |    Type    |      Default       | Description                                                                                                                                                                            |\n| -------------- | :--------: | :----------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `display_mode` |  `string`  |      `always`      | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when a `manifest.yml` file is present (or defined otherwise using `files`) </li></ul> |\n| `files`        | `[]string` | `[\"manifest.yml\"]` | on which files to display the segment on. Will look in parent folders as well                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{if .Org }}{{ .Org }}{{ end }}{{ if .Space }}/{{ .Space }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                |\n| -------- | -------- | -------------------------- |\n| `.Org`   | `string` | Cloud Foundry organization |\n| `.Space` | `string` | Cloud Foundry space        |\n| `.URL`   | `string` | Cloud Foundry API URL      |\n| `.User`  | `string` | logged in user             |\n\n[templates]: /docs/configuration/templates\n[cf-target]: https://cli.cloudfoundry.org/en-US/v8/target.html\n"
  },
  {
    "path": "website/docs/segments/cloud/gcp.mdx",
    "content": "---\nid: gcp\ntitle: GCP Context\nsidebar_label: GCP\n---\n\n## What\n\nDisplay the currently active [GCP][gcp] project, region and account\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"gcp\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#47888d\",\n    template: \" \\udb84\\uddf6 {{.Project}} :: {{.Account}} \",\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Project }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name            | Type     | Description                                                              |\n| --------------- | -------- | ------------------------------------------------------------------------ |\n| `.Project`      | `string` | the currently active project                                             |\n| `.Account`      | `string` | the currently active account                                             |\n| `.Region`       | `string` | default region for the active context                                    |\n| `.ActiveConfig` | `string` | the active configuration name                                            |\n| `.Error`        | `string` | contains any error messages generated when trying to load the GCP config |\n\n[templates]: /docs/configuration/templates\n[gcp]: https://cloud.google.com/\n"
  },
  {
    "path": "website/docs/segments/cloud/pulumi.mdx",
    "content": "---\nid: pulumi\ntitle: Pulumi\nsidebar_label: Pulumi\n---\n\n## What\n\nDisplay the currently active [Pulumi][pulumi] logged-in user, url and stack.\n\n:::caution\nThis requires a pulumi binary in your PATH and will only show in directories that contain a `Pulumi.yaml` file.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"pulumi\",\n    style: \"diamond\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#662d91\",\n    template:\n      \"\\ue873 {{ .Stack }}{{if .User }} :: {{ .User }}@{{ end }}{{ if .URL }}{{ .URL }}{{ end }}\",\n  }}\n/>\n\n## Options\n\n| Name          | Type      | Default | Description                                                                        |\n| ------------- | :-------: | :-----: | ---------------------------------------------------------------------------------- |\n| `fetch_stack` | `boolean` | `false` | fetch the current stack name                                                       |\n| `fetch_about` | `boolean` | `false` | fetch the URL and user for the current stask. Requires `fetch_stack` set to `true` |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n\\ue873 {{ .Stack }}{{if .User }} :: {{ .User }}@{{ end }}{{ if .URL }}{{ .URL }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Stack` | `string` | the current stack name                             |\n| `.User`  | `string` | is the current logged in user                      |\n| `.Url`   | `string` | the URL of the state where pulumi stores resources |\n\n[templates]: /docs/configuration/templates\n[pulumi]: https://www.pulumi.com/\n"
  },
  {
    "path": "website/docs/segments/cloud/sitecore.mdx",
    "content": "---\nid: sitecore\ntitle: Sitecore\nsidebar_label: Sitecore\n---\n\nimport Config from \"@site/src/components/Config.js\";\n\n## What\n\nDisplay current [Sitecore] environment. Will not be active when sitecore.json and user.json don't exist.\n\n## Sample Configuration\n\n<Config\n  data={{\n    type: \"sitecore\",\n    style: \"plain\",\n    foreground: \"#000000\",\n    background: \"#FFFFFF\",\n    template:\n      \"Env: {{ .EndpointName }}{{ if .CmHost }} CM: {{ .CmHost }}{{ end }}\",\n  }}\n/>\n\n## Options\n\n| Name              |   Type    | Default | Description                                                                     |\n| ----------------- | :-------: | :-----: | ------------------------------------------------------------------------------- |\n| `display_default` | `boolean` | `true`  | display the segment or not when the Sitecore environment name matches `default` |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .EndpointName }} {{ if .CmHost }}({{ .CmHost }}){{ end }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type     | Description                              |\n| -------------- | -------- | ---------------------------------------- |\n| `EndpointName` | `string` | name of the current Sitecore environment |\n| `CmHost`       | `string` | host of the current Sitecore environment |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[Sitecore]: https://www.sitecore.com/\n"
  },
  {
    "path": "website/docs/segments/health/nightscout.mdx",
    "content": "---\nid: nightscout\ntitle: Nightscout\nsidebar_label: Nightscout\n---\n\n## What\n\n[Nightscout][nightscout] (CGM in the Cloud) is an open source,\nDIY project that allows real time access to a CGM data via an HTTP REST API. It\nis used for secure remote viewing of blood sugar data from anywhere...including\nOh My Posh segments on the command line!\n\n## Sample Configuration\n\nThis example is using mg/dl by default because the Nightscout API sends the sugar\nglucose value (.Sgv) in mg/dl format. Below is also a template for displaying the\nglucose value in mmol/L. When using different color ranges you should multiply your\nhigh and low range glucose values by 18 and use these values in the templates.\nYou'll also want to think about your background and foreground colors. Don't use\nwhite text on a yellow background, for example.\n\nThe `foreground_templates` example below could be set to just a single color,\nif that color is visible against any of your backgrounds.\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"nightscout\",\n    style: \"diamond\",\n    foreground: \"#ffffff\",\n    background: \"#ff0000\",\n    background_templates: [\n      \"{{ if gt .Sgv 150 }}#FFFF00{{ end }}\",\n      \"{{ if lt .Sgv 60 }}#FF0000{{ end }}\",\n      \"#00FF00\",\n    ],\n    foreground_templates: [\n      \"{{ if gt .Sgv 150 }}#000000{{ end }}\",\n      \"{{ if lt .Sgv 60 }}#000000{{ end }}\",\n      \"#000000\",\n    ],\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\uE0B0\",\n    template: \"\\ue2a1 {{ .Sgv }}{{ .TrendIcon }}\",\n    options: {\n      url: \"https://YOURNIGHTSCOUTAPP.herokuapp.com/api/v1/entries.json?count=1&token=APITOKENFROMYOURADMIN\",\n      http_timeout: 1500,\n    },\n  }}\n/>\n\nOr display in mmol/l (instead of the default mg/dl) with the following template:\n\n<Config\n  data={{\n    template:\n      \"\\ue2a1 {{ if eq (mod .Sgv 18) 0 }}{{divf .Sgv 18}}.0{{ else }} {{ round (divf .Sgv 18) 1 }}{{ end }}{{ .TrendIcon }}\",\n  }}\n/>\n\n## Options\n\n| Name           |          Type           | Default | Description                                                                                                                                                                  |\n| -------------- | :---------------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `url`          | [`template`][templates] |         | Your Nightscout URL, including the full path to entries.json AND count=1 AND token. Example above. You'll know this works if you can curl it yourself and get a single value |\n| `headers`      |   `map[string]string`   |         | A key, value map of Headers to send with the request                                                                                                                         |\n| `http_timeout` |          `int`          |  `20`   | in milliseconds - how long do you want to wait before you want to see your prompt more than your sugar? I figure a half second is a good default                             |\n\n:::info\nYou can change the icons for trend, put the trend elsewhere, add text, however you like!\nMake sure your NerdFont has the glyph you want or [search for one][nf-search].\n\n| Icon                | Description      |\n| ------------------- | ---------------- |\n| `DoubleUpIcon`      | defaults to `↑↑` |\n| `SingleUpIcon`      | defaults to `↑`  |\n| `FortyFiveUpIcon`   | defaults to `↗`  |\n| `FlatIcon`          | defaults to `→`  |\n| `FortyFiveDownIcon` | defaults to `↘`  |\n| `SingleDownIcon`    | defaults to `↓`  |\n| `DoubleDownIcon`    | defaults to `↓↓` |\n\n:::\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Sgv }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                                                                                |\n| ------------- | -------- | ---------------------------------------------------------------------------------------------------------- |\n| `.ID`         | `string` | The internal ID of the object                                                                              |\n| `.Sgv`        | `int`    | Your Serum Glucose Value (your sugar)                                                                      |\n| `.Date`       | `int`    | The unix timestamp of the entry                                                                            |\n| `.DateString` | `time`   | The timestamp of the entry                                                                                 |\n| `.Trend`      | `int`    | The trend of the entry                                                                                     |\n| `.Device`     | `string` | The device linked to the entry                                                                             |\n| `.Type`       | `string` | The type of the entry                                                                                      |\n| `.UtcOffset`  | `int`    | The UTC offset                                                                                             |\n| `.SysTime`    | `time`   | The time on the system                                                                                     |\n| `.Mills`      | `int`    | The amount of mills                                                                                        |\n| `.TrendIcon`  | `string` | By default, this will be something like ↑↑ or ↘ etc but you can override them with any glyph as seen above |\n\n[templates]: /docs/configuration/templates\n[nightscout]: http://www.nightscout.info/\n[nf-search]: https://www.nerdfonts.com/cheat-sheet\n"
  },
  {
    "path": "website/docs/segments/health/ramadan.mdx",
    "content": "---\nid: ramadan\ntitle: Ramadan\nsidebar_label: Ramadan\n---\n\n## What\n\nDisplays Sehar (Fajr) and Iftar (Maghrib) prayer times along with a countdown to the next\nevent during Ramadan. Powered by the free [Aladhan Prayer Times API][aladhan]. The segment\nauto-hides when it is not Ramadan (configurable via `hide_outside_ramadan`).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"ramadan\",\n    style: \"diamond\",\n    foreground: \"#ffffff\",\n    background: \"#1a472a\",\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\ue0b0\",\n    template:\n      \"\\U0001F319 Roza {{.RozaNumber}} \\u00b7 {{.NextEvent}} in {{.TimeRemaining}}\",\n    options: {\n      city: \"Lahore\",\n      country: \"PK\",\n      method: 1,\n      school: 1\n    }\n  }}\n/>\n\n## Options\n\n| Name                   |   Type    | Default | Description                                                                  |\n| ---------------------- | :-------: | :-----: | ---------------------------------------------------------------------------- |\n| `latitude`             | `float64` |   `0`   | Latitude for prayer time calculation (use with `longitude`)                  |\n| `longitude`            | `float64` |   `0`   | Longitude for prayer time calculation (use with `latitude`)                  |\n| `city`                 | `string`  |  `\"\"`   | City name for location lookup — takes precedence over `latitude`/`longitude` |\n| `country`              | `string`  |  `\"\"`   | Country name or ISO 3166 alpha-2 code — required when using `city`           |\n| `method`               |   `int`   |   `3`   | Prayer calculation method (0–23, 99). See [Aladhan methods][methods] for details |\n| `school`               |   `int`   |   `0`   | Madhab school: `0` = Shafi (standard), `1` = Hanafi                          |\n| `hide_outside_ramadan` |  `bool`   | `true`  | Hide the segment when not in Ramadan                                         |\n| `first_roza_date`      | `string`  |  `\"\"`   | Override first day of Ramadan as `YYYY-MM-DD` for local moon sighting        |\n| `http_timeout`         |   `int`   |  `20`   | HTTP request timeout in milliseconds                                         |\n\n:::info\nEither **city + country** or **latitude + longitude** must be configured. If both are\nprovided, `city` + `country` takes precedence.\n:::\n\n:::tip Prayer calculation methods\n\nUse the method associated with the issuing authority closest to your location.\nThe full ID→authority mapping is:\n\n| ID  | Authority                                                      |\n| --- | -------------------------------------------------------------- |\n| 0   | Shia Ithna-Ashari, Leva Institute, Qum                         |\n| 1   | University of Islamic Sciences, Karachi                        |\n| 2   | Islamic Society of North America (ISNA)                        |\n| 3   | Muslim World League (**default**)                              |\n| 4   | Umm Al-Qura University, Makkah                                 |\n| 5   | Egyptian General Authority of Survey                           |\n| 7   | Institute of Geophysics, University of Tehran                  |\n| 8   | Gulf Region                                                    |\n| 9   | Kuwait                                                         |\n| 10  | Qatar                                                          |\n| 11  | Majlis Ugama Islam Singapura, Singapore                        |\n| 12  | Union Organisation Islamique de France                         |\n| 13  | Diyanet İşleri Başkanlığı, Turkey *(experimental)*             |\n| 14  | Spiritual Administration of Muslims of Russia                  |\n| 15  | Moonsighting Committee Worldwide                               |\n| 16  | Dubai *(experimental)*                                         |\n| 17  | Jabatan Kemajuan Islam Malaysia (JAKIM)                        |\n| 18  | Tunisia                                                        |\n| 19  | Algeria                                                        |\n| 20  | Kementerian Agama Republik Indonesia                           |\n| 21  | Morocco                                                        |\n| 22  | Comunidade Islâmica de Lisboa, Portugal                        |\n| 23  | Ministry of Awqaf, Islamic Affairs and Holy Places, Jordan     |\n| 99  | Custom (use `methodSettings` via the API)                      |\n\nNote: ID 6 is not assigned.\n:::\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n 🌙 Roza {{.RozaNumber}} · {{.NextEvent}} in {{.TimeRemaining}}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                                     |\n| ---------------- | -------- | --------------------------------------------------------------- |\n| `.Fajr`          | `string` | Sehar (Fajr) time in `HH:MM` format                             |\n| `.Iftar`         | `string` | Iftar (Maghrib) time in `HH:MM` format                          |\n| `.Imsak`         | `string` | Imsak time in `HH:MM` format (~10 min before Fajr)              |\n| `.RozaNumber`    | `int`    | Day number within Ramadan (1–30)                                |\n| `.NextEvent`     | `string` | Name of the next event: `Sehar` or `Iftar`                      |\n| `.TimeRemaining` | `string` | Countdown to the next event, e.g. `3h 42m`                      |\n| `.Fasting`       | `bool`   | `true` when currently between Fajr and Maghrib (fasting window) |\n\n[templates]: /docs/configuration/templates\n[aladhan]: https://aladhan.com/prayer-times-api\n[methods]: https://aladhan.com/calculation-methods\n"
  },
  {
    "path": "website/docs/segments/health/strava.mdx",
    "content": "---\nid: strava\ntitle: Strava\nsidebar_label: Strava\n---\n\n## What\n\n[Strava][strava] is a popular activity tracker for bike, run or any other training.\nTo keep up with your training goals it is important to be reminded about it.\nAn Oh My Posh Strava segment shows your last activity,\nand can also indicate by a color if it is time to get away from your computer and get active.\n\n## Accessing your Strava data\n\nTo allow Oh My Posh access your Strava data you need to grant access to read your public activities.\nThis will give you an access and a refresh token. Paste the tokens into your Strava segment configuration.\n\nClick the following link to connect with Strava:\n\n[![strava-connect](/img/strava_connect.svg)][strava-connect]\n\n## Sample Configuration\n\nThis configuration sets the background green if you have an activity the last two days,\norange if you have one last 5 days, and red otherwise. The `foreground_templates` example below could be set to just a single color,\nif that color is visible against any of your backgrounds.\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"strava\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#000000\",\n    background_templates: [\n      \"{{ if gt .Hours 100 }}#dc3545{{ end }}\",\n      \"{{ if and (lt .Hours 100) (gt .Hours 50) }}#ffc107{{ end }}\",\n      \"{{ if lt .Hours 50 }}#28a745{{ end }}\",\n    ],\n    foreground_templates: [\n      \"{{ if gt .Hours 100 }}#FFFFFF{{ end }}\",\n      \"{{ if and (lt .Hours 100) (gt .Hours 50) }}#343a40{{ end }}\",\n      \"{{ if lt .Hours 50 }}#FFFFFF{{ end }}\",\n    ],\n    template: \" \\ued52 {{.Name}} {{.Ago}} {{.Icon}} \",\n    options: {\n      access_token: \"11111111111111111\",\n      refresh_token: \"1111111111111111\",\n      http_timeout: 1500,\n    },\n  }}\n/>\n\n## Options\n\n| Name                    |          Type           | Default  | Description                                                                                                   |\n| ----------------------- | :---------------------: | :------: | ------------------------------------------------------------------------------------------------------------- |\n| `access_token`          | [`template`][templates] |          | token from Strava login, see login link in section above.                                                     |\n| `refresh_token`         | [`template`][templates] |          | token from Strava login, see login link in section above.                                                     |\n| `expires_in`            |          `int`          |   `0`    | the default timeout of the token from the Strava login                                                        |\n| `http_timeout`          |          `int`          |   `20`   | in milliseconds - how long do you want to wait before you want to see your prompt more than your strava data? |\n| `ride_icon`             |        `string`         | `\\uf206` |                                                                                                               |\n| `run_icon`              |        `string`         | `\\ue213` |                                                                                                               |\n| `skiing_icon`           |        `string`         | `\\ue213` |                                                                                                               |\n| `workout_icon`          |        `string`         | `\\ue213` |                                                                                                               |\n| `unknown_activity_icon` |        `string`         | `\\ue213` |                                                                                                               |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .Error }}{{ .Error }}{{ else }}{{ .Ago }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name                    | Type      | Description                         |\n| ----------------------- | --------- | ----------------------------------- |\n| `.ID`                   | `time`    | The id of the entry                 |\n| `.DateString`           | `time`    | The timestamp of the entry          |\n| `.Type`                 | `string`  | Activity types as used in strava    |\n| `.UtcOffset`            | `int`     | The UTC offset                      |\n| `.Hours`                | `int`     | Number of hours since last activity |\n| `.Name`                 | `string`  | The name of the activity            |\n| `.Duration`             | `float64` | Total duration in seconds           |\n| `.Distance`             | `float64` | Total distance in meters            |\n| `.DeviceWatts`          | `bool`    | Device has watts                    |\n| `.AverageWatts`         | `float64` | Average watts                       |\n| `.WeightedAverageWatts` | `float64` | Weighted average watts              |\n| `.AverageHeartRate`     | `float64` | Average heart rate                  |\n| `.MaxHeartRate`         | `float64` | Max heart rate                      |\n| `.KudosCount`           | `int`     | Kudos count                         |\n| `.Icon`                 | `string`  | Activity based icon                 |\n\nNow, go out and have a fun ride or run!\n\n[templates]: /docs/configuration/templates\n[strava]: http://www.strava.com/\n[strava-connect]: https://www.strava.com/oauth/authorize?client_id=76033&response_type=code&redirect_uri=https://ohmyposh.dev/api/auth&approval_prompt=force&scope=read,activity:read&state=strava\n"
  },
  {
    "path": "website/docs/segments/health/withings.mdx",
    "content": "---\nid: withings\ntitle: Withings\nsidebar_label: Withings\n---\n\nimport WithingsConnect from \"/img/withings.svg\";\n\n## What\n\nThe [Withings][withings] health ecosystem of connected devices & apps is designed to improve daily wellbeing\nand long-term health.\n\n## Accessing your Withings data\n\nTo allow Oh My Posh access your Withings data you need to grant access to read your public activities.\nThis will give you an access and a refresh token. Paste the tokens into your Withings segment configuration.\n\nClick the following link to connect with Withings:\n\n<a\n  href=\"https://account.withings.com/oauth2_user/authorize2?client_id=93675962e88ddfe53f83c0c900558f72174e0ac70ccfb57e48053530c7e6e494&response_type=code&redirect_uri=https://ohmyposh.dev/api/auth&scope=user.activity,user.metrics&state=withings\"\n  className=\"withings\"\n>\n  <WithingsConnect />\n</a>\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"withings\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#000000\",\n    template: \"{{ if gt .Weight 0.0 }} {{ round .Weight 2 }}kg {{ end }}\",\n    options: {\n      access_token: \"11111111111111111\",\n      refresh_token: \"1111111111111111\",\n      http_timeout: 1500,\n    },\n  }}\n/>\n\n## Options\n\n| Name            |          Type           | Default | Description                                                                                   |\n| --------------- | :---------------------: | :-----: | --------------------------------------------------------------------------------------------- |\n| `access_token`  | [`template`][templates] |         | token from Withings login, see login link in section above.                                   |\n| `refresh_token` | [`template`][templates] |         | token from Withings login, see login link in section above.                                   |\n| `expires_in`    |          `int`          |   `0`   | the default timeout of the token from the Withings login                                      |\n| `http_timeout`  |          `int`          |  `20`   | how long do you want to wait before you want to see your prompt more than your Withings data? |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if gt .Weight 0.0 }} {{ round .Weight 2 }}kg {{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                         |\n| ------------- | -------- | ----------------------------------- |\n| `.Weight`     | `float`  | your last measured weight           |\n| `.SleepHours` | `string` | your last measured sleep SleepHours |\n| `.Steps`      | `int`    | your last measured steps            |\n\nNow, go out and be active!\n\n[templates]: /docs/configuration/templates\n[withings]: https://www.withings.com/\n"
  },
  {
    "path": "website/docs/segments/languages/clojure.mdx",
    "content": "---\nid: clojure\ntitle: Clojure\nsidebar_label: Clojure\n---\n\n## What\n\nDisplay the currently active [Clojure][clojure] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"clojure\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#9068B0\",\n    template: \" \\uE768 {{ .Full }}\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                              Default                               | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                              `false`                               | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                              `true`                                | fetch the clojure version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |                              `none`                                | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                                    | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                             `context`                              | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                                    | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `project.clj, deps.edn, build.boot, bb.edn, *.clj, *.cljc, *.cljs` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                                    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                          `clojure, lein`                           | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: configuration/templates.mdx\n[clojure]: https://clojure.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/crystal.mdx",
    "content": "---\nid: crystal\ntitle: Crystal\nsidebar_label: Crystal\n---\n\n## What\n\nDisplay the currently active [crystal] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"crystal\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\ue62f {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |      Default      | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |      `false`      | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |      `true`       | fetch the crystal version                                                                                                                                                                                                            |\n| `cache_duration`       |  `string`  |      `none`       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |     `context`     | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.cr, shard.yml` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                   | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |     `crystal`     | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[crystal]: https://crystal-lang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/dart.mdx",
    "content": "---\nid: dart\ntitle: Dart\nsidebar_label: Dart\n---\n\n## What\n\nDisplay the currently active [Dart][dart] version. Supports [fvm].\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"dart\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#06A4CE\",\n    template: \" \\uE798 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                      Default                      | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                      `false`                      | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                      `true`                       | fetch the dart version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |                       `none`                       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                     `context`                     | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.dart, pubspec.yaml, pubspec.yml, pubspec.lock` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                   `.dart_tool`                    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                    `fvm, dart`                    | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[dart]: https://dart.dev/\n[fvm]: https://fvm.app/\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/dotnet.mdx",
    "content": "---\nid: dotnet\ntitle: Dotnet\nsidebar_label: Dotnet\n---\n\n## What\n\nDisplay the currently active [.NET SDK][net-sdk-docs] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"dotnet\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#00ffff\",\n    template: \" \\uE77F {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                                              Default                                               | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                                              `false`                                               | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                                               `true`                                               | fetch the active version or not; useful if all you need is an icon indicating `dotnet`                                                                                                                                               |\n| `cache_duration`       |  `string`  |                                               `none`                                               | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                                                                    | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                                             `context`                                              | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                                                                    | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.cs, *.csx, *.vb, *.fs, *.fsx, *.sln, *.slnf, *.slnx, *.csproj, *.fsproj, *.vbproj, global.json` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                                                                    | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                                              `dotnet`                                              | the tooling to use for fetching the version                                                                                                                                                                                          |\n| `fetch_sdk_version`    | `boolean`  |                                              `false`                                               | fetch the SDK version in `global.json` when present                                                                                                                                                                                  |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Unsupported }}\\uf071{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                                         |\n| ---------------- | -------- | ------------------------------------------------------------------- |\n| `.Full`          | `string` | the full version                                                    |\n| `.Major`         | `string` | major number                                                        |\n| `.Minor`         | `string` | minor number                                                        |\n| `.Patch`         | `string` | patch number                                                        |\n| `.Prerelease`    | `string` | prerelease info text                                                |\n| `.BuildMetadata` | `string` | build metadata                                                      |\n| `.URL`           | `string` | URL of the version info / release notes                             |\n| `.SDKVersion`    | `string` | the SDK version in `global.json` when `fetch_sdk_version` is `true` |\n| `.Error`         | `string` | error encountered when fetching the version string                  |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[net-sdk-docs]: https://docs.microsoft.com/en-us/dotnet/core/tools\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/elixir.mdx",
    "content": "---\nid: elixir\ntitle: Elixir\nsidebar_label: Elixir\n---\n\n## What\n\nDisplay the currently active [Elixir][elixir] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"elixir\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#422251\",\n    template: \" \\ue62d {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |     Default    | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |     `true`     | fetch the elixir version                                                                                                                                                                                                             |\n| `cache_duration`       |  `string`  |     `none`     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.ex, *.exs`  | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` | `asdf, elixir` | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[elixir]: https://elixir-lang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/fortran.mdx",
    "content": "---\nid: fortran\ntitle: Fortran\nsidebar_label: Fortran\n---\n\n## What\n\nDisplay the currently active [fortran] compiler version.\n\n:::warning Compiler support\n\nThis only works with the [gfortran] compiler.\n\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"fortran\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#422251\",\n    template: \" \\udb84\\ude1a {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                                                 Default                                                 | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                                                 `false`                                                 | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                                                 `true`                                                  | fetch the gfortran version                                                                                                                                                                                                           |\n| `cache_duration`       |  `string`  |                                                 `none`                                                  | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                                                                         | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                                                `context`                                                | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                                                                         | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `fpm.toml, *.f, *.for, *.fpp, *.f77, *.f90, *.f95, *.f03, *.f08` + uppercase equivalents (`*.F` etc...) | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                                                                         | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                                                `gfortran`                                               | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[fortran]: https://fortran-lang.org/\n[gfortran]: https://fortranwiki.org/fortran/show/GFortran\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/golang.mdx",
    "content": "---\nid: golang\ntitle: Golang\nsidebar_label: Golang\n---\n\n## What\n\nDisplay the currently active [Golang][golang] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"go\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#7FD5EA\",\n    template: \" \\ue627 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                   Default                    | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                   `false`                    | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                    `true`                    | fetch the golang version                                                                                                                                                                                                             |\n| `cache_duration`       |  `string`  |                    `none`                    | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                              | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                  `context`                   | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                              | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `parse_mod_file`       | `boolean`  |                   `false`                    | parse the go.mod file instead of calling `go version`                                                                                                                                                                                |\n| `parse_go_work_file`   | `boolean`  |                   `false`                    | parse the go.work file instead of calling `go version`                                                                                                                                                                               |\n| `extensions`           | `[]string` | `*.go, go.mod, go.work, go.sum, go.work.sum` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                              | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                   `mod, go`                  | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[golang]: https://go.dev/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/haskell.mdx",
    "content": "---\nid: haskell\ntitle: Haskell\nsidebar_label: Haskell\n---\n\n## What\n\nDisplay the currently active Glasgow [Haskell][haskell] Compiler (GHC) version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"haskell\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#906cff\",\n    background: \"#100e23\",\n    template: \" \\ue61f {{ .Full }}\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                             Default                             | Description                                                                                                                                                                                                                                                                                    |\n| ---------------------- | :--------: | :-------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `home_enabled`         | `boolean`  |                             `false`                             | display the segment in the HOME folder or not                                                                                                                                                                                                                                                  |\n| `fetch_version`        | `boolean`  |                             `true`                              | fetch the GHC version                                                                                                                                                                                                                                                                          |\n| `cache_duration`       |  `string`  |                             `none`                              | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`                                                                        |\n| `missing_command_text` |  `string`  |                                                                 | text to display when the command is missing                                                                                                                                                                                                                                                    |\n| `display_mode`         |  `string`  |                            `context`                            | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul>                                                           |\n| `version_url_template` |  `string`  |                                                                 | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                                                                          |\n| `stack_ghc_mode`       |  `string`  |                             `never`                             | determines when to use `stack ghc` to retrieve the version information. Using `stack ghc` will decrease performance.<ul><li>`never`: never use `stack ghc`</li><li>`package`: only use `stack ghc` when `stack.yaml` is in the root of the </li><li>`always`: always use `stack ghc`</li></ul> |\n| `extensions`           | `[]string` | `*.hs, *.lhs, stack.yaml, package.yaml, *.cabal, cabal.project` | allows to override the default list of file extensions to validate                                                                                                                                                                                                                             |\n| `folders`              | `[]string` |                                                                 | allows to override the list of folder names to validate                                                                                                                                                                                                                                        |\n| `tooling`              | `[]string` |                              `ghc`                              | the tooling to use for fetching the version. Available options: `ghc`, `stack`                                                                                                                                                                                                                 |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name        | Type      | Description                                        |\n| ----------- | --------- | -------------------------------------------------- |\n| `.Full`     | `string`  | the full version                                   |\n| `.Major`    | `string`  | major number                                       |\n| `.Minor`    | `string`  | minor number                                       |\n| `.Patch`    | `string`  | patch number                                       |\n| `.URL`      | `string`  | URL of the version info / release notes            |\n| `.Error`    | `string`  | error encountered when fetching the version string |\n| `.StackGhc` | `boolean` | `true` if `stack ghc` was used, otherwise `false`  |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[haskell]: https://www.haskell.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/java.mdx",
    "content": "---\nid: java\ntitle: Java\nsidebar_label: Java\n---\n\n## What\n\nDisplay the currently active [Java][java] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"java\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\uE738 {{ .Full }}\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                                                                  Default                                                                   | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------------------------------------------------------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                                                                  `false`                                                                   | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                                                                   `true`                                                                   | fetch the java version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |                                                                   `none`                                                                   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                                                                                                            | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                                                                 `context`                                                                  | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                                                                                                            | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.java, *.class, *.gradle, *.jar, *.clj, *.cljr, pom.xml, build.gradle.kts, build.sbt, .java-version, .deps.edn, project.clj, build.boot` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                                                                                                            | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                                                                   `java`                                                                   | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: configuration/templates.mdx\n[java]: https://www.java.com/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/julia.mdx",
    "content": "---\nid: julia\ntitle: Julia\nsidebar_label: Julia\n---\n\n## What\n\nDisplay the currently active [Julia][julia] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"julia\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\uE624 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |  Default  | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |  `false`  | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |  `true`   | fetch the julia version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |  `none`   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  | `context` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` |  `*.jl`   | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |  `julia`  | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[julia]: https://julialang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/kotlin.mdx",
    "content": "---\nid: kotlin\ntitle: Kotlin\nsidebar_label: Kotlin\n---\n\n## What\n\nDisplay the currently active [Kotlin][kotlin] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"kotlin\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#906cff\",\n    template: \" \\ue634 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n## Options\n\n| Name                   |    Type    |       Default        | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |       `false`        | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |        `true`        | fetch the kotlin version                                                                                                                                                                                                             |\n| `cache_duration`       |  `string`  |        `none`        | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                      | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |      `context`       | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                      | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.kt, *.kts, *.ktm` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                      | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |      `kotlin`        | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[kotlin]: https://kotlinlang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/lua.mdx",
    "content": "---\nid: lua\ntitle: Lua\nsidebar_label: Lua\n---\n\n## What\n\nDisplay the currently active [Lua][lua] or [LuaJIT][luajit] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"lua\",\n    style: \"powerline\",\n    powerline_symbol: \"\\ue0b0\",\n    foreground: \"white\",\n    background: \"blue\",\n    template: \" \\ue620 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |       Default       | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |       `false`       | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |       `true`        | fetch the lua version                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |       `none`        | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                     | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |      `context`      | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                     | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.lua, *.rockspec` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |        `lua`        | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |   `lua, luajit`     | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                        |\n| ------------- | -------- | -------------------------------------------------- |\n| `.Full`       | `string` | the full version                                   |\n| `.Major`      | `string` | major number                                       |\n| `.Minor`      | `string` | minor number                                       |\n| `.Patch`      | `string` | patch number                                       |\n| `.URL`        | `string` | URL of the version info / release notes            |\n| `.Error`      | `string` | error encountered when fetching the version string |\n| `.Executable` | `string` | the executable used to fetch the version           |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[lua]: https://www.lua.org/\n[luajit]: https://luajit.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/mojo.mdx",
    "content": "---\nid: mojo\ntitle: Mojo\nsidebar_label: Mojo\n---\n\n## What\n\nDisplay the currently active version of [Mojo][mojo] and the name of the [Magic][magic] virtual environment.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"mojo\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#100e23\",\n    background: \"#906cff\",\n    template: \" 🔥 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |             Default              | Description                                                                                                                                                                                                                                                                                                             |\n| ---------------------- | :--------: | :------------------------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `home_enabled`         | `boolean`  |             `false`              | display the segment in the HOME folder or not                                                                                                                                                                                                                                                                           |\n| `fetch_virtual_env`    | `boolean`  |             `true`               | fetch the name of the virtualenv or not                                                                                                                                                                                                                                                                                 |\n| `display_default`      | `boolean`  |             `true`               | show the name of the virtualenv when it's equal to `default` or not                                                                                                                                                                                                                                                     |\n| `fetch_version`        | `boolean`  |             `true`               | fetch the Mojo version or not                                                                                                                                                                                                                                                                                           |\n| `cache_duration`       |  `string`  |             `none`               | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`                                                                                                 |\n| `missing_command_text` |  `string`  |                                  | text to display when the command is missing                                                                                                                                                                                                                                                                             |\n| `display_mode`         |  `string`  |          `environment`           | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`environment`: the segment is only displayed when in a virtual environment</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                  | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                                                                                                   |\n| `extensions`           | `[]string` | `*.🔥, *.mojo, mojoproject.toml` | allows to override the default list of file extensions to validate                                                                                                                                                                                                                                                      |\n| `folders`              | `[]string` |                                  | allows to override the list of folder names to validate                                                                                                                                                                                                                                                                 |\n| `tooling`              | `[]string` |             `mojo`               | the tooling to use for fetching the version                                                                                                                                                                                                                                                                             |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Venv`  | `string` | the virtual environment name (if present)          |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[mojo]: https://docs.modular.com/mojo\n[magic]: https://docs.modular.com/magic\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/nim.mdx",
    "content": "---\nid: nim\ntitle: Nim\nsidebar_label: Nim\n---\n\n## What\n\nDisplay the currently active [Nim][nim] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"nim\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#f3d400\",\n    template: \" \\ue841 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |               Default               | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :---------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |               `false`               | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |               `true`                | fetch the Nim version (`nim --version`)                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |               `none`                | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                     | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |              `context`              | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                     | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.nim, *.nims`                     | allows to override the default list of file extensions to validate                                                                                                                                                                  |\n| `folders`              | `[]string` |                                     | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |               `nim`                 | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                        |\n| ------------- | -------- | -------------------------------------------------- |\n| `.Full`       | `string` | the full version                                   |\n| `.Major`      | `string` | major number                                       |\n| `.Minor`      | `string` | minor number                                       |\n| `.Patch`      | `string` | patch number                                       |\n| `.Error`      | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[nim]: https://nim-lang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/node.mdx",
    "content": "---\nid: node\ntitle: Node\nsidebar_label: Node\n---\n\n## What\n\nDisplay the currently active [Node.js][node-js] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"node\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#6CA35E\",\n    template: \" \\uE718 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                    |    Type    |                                   Default                                    | Description                                                                                                                                                                                                                          |\n| ----------------------- | :--------: | :--------------------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`          | `boolean`  |                                   `false`                                    | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`         | `boolean`  |                                    `true`                                    | fetch the Node.js version                                                                                                                                                                                                            |\n| `cache_duration`        |  `string`  |                                    `none`                                    | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text`  |  `string`  |                                                                              | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`          |  `string`  |                                  `context`                                   | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template`  |  `string`  |                                                                              | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `fetch_package_manager` | `boolean`  |                                   `false`                                    | define if the current project uses PNPM, Yarn, or NPM                                                                                                                                                                                |\n| `pnpm_icon`             |  `string`  |                                   `\\ue865`                                   | the icon/text to display when using PNPM                                                                                                                                                                                             |\n| `yarn_icon`             |  `string`  |                                   `\\ue6a7`                                   | the icon/text to display when using Yarn                                                                                                                                                                                             |\n| `npm_icon`              |  `string`  |                                   `\\uE71E`                                   | the icon/text to display when using NPM                                                                                                                                                                                              |\n| `bun_icon`              |  `string`  |                                   `\\ue76f`                                   | the icon/text to display when using Bun                                                                                                                                                                                              |\n| `extensions`            | `[]string` | `*.js, *.ts, package.json, .nvmrc, pnpm-workspace.yaml, .pnpmfile.cjs, .vue` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`               | `[]string` |                                                                              | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`               | `[]string` |                                    `node`                                    | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}\n```\n\n:::\n\n### Properties\n\n| Name                  | Type      | Description                                                                                              |\n| --------------------- | --------- | -------------------------------------------------------------------------------------------------------- |\n| `.Full`               | `string`  | the full version                                                                                         |\n| `.Major`              | `string`  | major number                                                                                             |\n| `.Minor`              | `string`  | minor number                                                                                             |\n| `.Patch`              | `string`  | patch number                                                                                             |\n| `.URL`                | `string`  | URL of the version info / release notes                                                                  |\n| `.Error`              | `string`  | error encountered when fetching the version string                                                       |\n| `.PackageManagerName` | `string`  | the package manager name (`bun`, `npm`, `yarn` or `pnpm`) when setting `fetch_package_manager` to `true` |\n| `.PackageManagerIcon` | `string`  | the PNPM, Yarn, Bun, or NPM icon when setting `fetch_package_manager` to `true`                          |\n| `.Mismatch`           | `boolean` | true if the version in `.nvmrc` is not equal to `.Full`                                                  |\n| `.Expected`           | `string`  | the expected version set in `.nvmrc`                                                                     |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[node-js]: https://nodejs.org\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/ocaml.mdx",
    "content": "---\nid: ocaml\ntitle: Ocaml\nsidebar_label: Ocaml\n---\n\n## What\n\nDisplay the currently active [OCaml] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"ocaml\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#d08770\",\n    template: \" \\ue67a {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                      Default                      | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-----------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                      `false`                      | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                      `true`                       | display the ocaml version (`ocaml -version`)                                                                                                                                                                                         |\n| `cache_duration`       |  `string`  |                      `none`                       | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                   | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                     `context`                     | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                   | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.ml, *.mli, dune, dune-project, dune-workspace` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                   | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                     `ocaml`                       | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                        |\n| ------------- | -------- | -------------------------------------------------- |\n| `.Full`       | `string` | the full version                                   |\n| `.Major`      | `string` | major number                                       |\n| `.Minor`      | `string` | minor number                                       |\n| `.Patch`      | `string` | patch number                                       |\n| `.Prerelease` | `string` | channel name                                       |\n| `.Error`      | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[OCaml]: https://ocaml.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/perl.mdx",
    "content": "---\nid: perl\ntitle: Perl\nsidebar_label: Perl\n---\n\n## What\n\nDisplay the currently active [Perl][perl] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"perl\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\ue769 {{ .Full }}\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |             Default              | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |             `false`              | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |              `true`              | fetch the perl version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |              `none`              | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                  | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |            `context`             | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                  | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.pl, *.pm, *.t, .perl-version` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                  | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |             `perl`               | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[perl]: https://www.perl.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/php.mdx",
    "content": "---\nid: php\ntitle: PHP\nsidebar_label: PHP\n---\n\n## What\n\nDisplay the currently active [PHP][php] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"php\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\ue73d {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                             Default                            | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                             `false`                            | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                             `true`                             | fetch the php version                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |                             `none`                             | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                            `context`                           | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.php, .php-version, composer.json, composer.lock, blade.php` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |                             `php`                              | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[php]: https://www.php.net/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/python.mdx",
    "content": "---\nid: python\ntitle: Python\nsidebar_label: Python\n---\n\n## What\n\nDisplay the currently active [Python][python] version and [virtualenv].\nSupports [conda], virtualenv and pyenv (if python points to pyenv shim).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"python\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffd43b\",\n    background: \"#306998\",\n    template: \" \\uE235 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                    Default                     | Description                                                                                                                                                                                                                                                                                                             |\n| ---------------------- | :--------: | :--------------------------------------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `home_enabled`         | `boolean`  |                    `false`                     | display the segment in the HOME folder or not                                                                                                                                                                                                                                                                           |\n| `fetch_virtual_env`    | `boolean`  |                     `true`                     | fetch the name of the virtualenv or not                                                                                                                                                                                                                                                                                 |\n| `display_default`      | `boolean`  |                     `true`                     | show the name of the virtualenv when it's default (`system`, `base`) or not                                                                                                                                                                                                                                             |\n| `fetch_version`        | `boolean`  |                     `true`                     | fetch the python version                                                                                                                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |                     `none`                     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`                                                                                                 |\n| `missing_command_text` |  `string`  |                                                | text to display when the command is missing                                                                                                                                                                                                                                                                             |\n| `display_mode`         |  `string`  |                 `environment`                  | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`environment`: the segment is only displayed when in a virtual environment</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                                                                                                   |\n| `extensions`           | `[]string` |   `*.py, *.ipynb, pyproject.toml, venv.bak`    | allows to override the default list of file extensions to validate                                                                                                                                                                                                                                                      |\n| `folders`              | `[]string` | `.venv, venv, virtualenv, venv-win, pyenv-win` | allows to override the list of folder names to validate                                                                                                                                                                                                                                                                 |\n| `tooling`              | `[]string` |          `pyenv, python, python3, py`          | the tooling to use for fetching the version. Available options: `pyenv`, `python`, `python3`, `py`, `uv`                                                                                                                                                                                                                |\n| `folder_name_fallback` | `boolean`  |                     `true`                     | instead of `default_venv_names` (case sensitive), use the parent folder name as the virtual environment's name or not                                                                                                                                                                                                   |\n| `default_venv_names`   | `[]string` |                 `.venv, venv`                  | allows to override the list of environment's name replaced when `folder_name_fallback` is `true`                                                                                                                                                                                                                        |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .Error }}{{ .Error }}{{ else }}{{ if .Venv }}{{ .Venv }} {{ end }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Venv`  | `string` | the virtual environment name (if present)          |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[python]: https://www.python.org/\n[virtualenv]: https://virtualenv.pypa.io/\n[conda]: https://conda.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/r.mdx",
    "content": "---\nid: r\ntitle: R\nsidebar_label: R\n---\n\n## What\n\nDisplay the currently active [R][r-homepage] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"r\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"blue\",\n    background: \"lightWhite\",\n    template: \" \\ue68a {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                        Default                         | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                        `false`                         | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                         `true`                         | fetch the R version or not                                                                                                                                                                                                           |\n| `cache_duration`       |  `string`  |                         `none`                         | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                                        | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                       `context`                        | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                                        | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.R, *.Rmd, *.Rsx, *.Rda, *.Rd, *.Rproj, .Rproj.user` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                                        | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |               `Rscript, R, R.exe`                      | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[r-homepage]: https://www.r-project.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/ruby.mdx",
    "content": "---\nid: ruby\ntitle: Ruby\nsidebar_label: Ruby\n---\n\n## What\n\nDisplay the currently active [Ruby][ruby] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"ruby\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#4063D8\",\n    template: \" \\uE791 {{ .Full }}\",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |                 Default                 | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |                 `false`                 | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |                 `true`                  | fetch the ruby version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |                 `none`                  | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                         | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |                `context`                | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                         | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` |        `*.rb, Rakefile, Gemfile`        | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                         | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` | `rbenv, rvm-prompt, chruby, asdf, ruby` | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[ruby]: https://www.ruby-lang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/rust.mdx",
    "content": "---\nid: rust\ntitle: Rust\nsidebar_label: Rust\n---\n\n## What\n\nDisplay the currently active [Rust][rust] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"rust\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#99908a\",\n    template: \" \\uE7a8 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |            Default             | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |            `false`             | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |             `true`             | fetch the rust version (`rustc --version`)                                                                                                                                                                                           |\n| `cache_duration`       |  `string`  |             `none`             | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |           `context`            | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.rs, Cargo.toml, Cargo.lock` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |            `rustc`             | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                        |\n| ------------- | -------- | -------------------------------------------------- |\n| `.Full`       | `string` | the full version                                   |\n| `.Major`      | `string` | major number                                       |\n| `.Minor`      | `string` | minor number                                       |\n| `.Patch`      | `string` | patch number                                       |\n| `.Prerelease` | `string` | channel name                                       |\n| `.Error`      | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[rust]: https://rust-lang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/swift.mdx",
    "content": "---\nid: swift\ntitle: Swift\nsidebar_label: Swift\n---\n\n## What\n\nDisplay the currently active [Swift][swift] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"swift\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#f6553c\",\n    template: \" \\ue755 {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |           Default           | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |           `false`           | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |           `true`            | fetch the swift version                                                                                                                                                                                                              |\n| `cache_duration`       |  `string`  |           `none`            | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                             | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |          `context`          | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                             | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.swift, *.SWIFT, Podfile` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                             | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |           `swift`           | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.Patch` | `string` | patch number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[swift]: https://www.swift.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/v.mdx",
    "content": "---\nid: v\ntitle: V\nsidebar_label: V\n---\n\n## What\n\nDisplay the currently active [V][v-lang] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"v\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#4F87FF\",\n    template: \" \\ue6ac {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |  Default  | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |  `false`  | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |  `true`   | fetch the V version (`v --version`)                                                                                                                                                                                                  |\n| `cache_duration`       |  `string`  |  `none`   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  | `context` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` |   `*.v`   | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |    `v`    | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type     | Description                                        |\n| ------------- | -------- | -------------------------------------------------- |\n| `.Full`       | `string` | the full version (e.g., \"0.4.9\")                  |\n| `.Major`      | `string` | major number (e.g., \"0\")                          |\n| `.Minor`      | `string` | minor number (e.g., \"4\")                          |\n| `.Patch`      | `string` | patch number (e.g., \"9\")                          |\n| `.Commit`     | `string` | commit hash (e.g., \"b487986\")                     |\n| `.Error`      | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[v-lang]: https://vlang.io/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/vala.mdx",
    "content": "---\nid: vala\ntitle: Vala\nsidebar_label: Vala\n---\n\n## What\n\nDisplay the currently active [Vala][vala] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"vala\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#5E20A4\",\n    template: \" \\ue69e {{ .Full }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |  Default  | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |  `false`  | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |  `true`   | fetch the vala version                                                                                                                                                                                                               |\n| `cache_duration`       |  `string`  |  `none`   | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |           | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  | `context` | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |           | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.vala`  | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |           | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |  `vala`   | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name     | Type     | Description                                        |\n| -------- | -------- | -------------------------------------------------- |\n| `.Full`  | `string` | the full version                                   |\n| `.Major` | `string` | major number                                       |\n| `.Minor` | `string` | minor number                                       |\n| `.URL`   | `string` | URL of the version info / release notes            |\n| `.Error` | `string` | error encountered when fetching the version string |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[vala]: https://vala.dev/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/languages/zig.mdx",
    "content": "---\nid: zig\ntitle: Zig\nsidebar_label: Zig\n---\n\n## What\n\nDisplay the currently active [Zig][zig] version.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"zig\",\n    style: \"powerline\",\n    powerline_symbol: \"\\ue0b0\",\n    foreground: \"#342311\",\n    background: \"#ffad55\",\n    template:\n      \" \\ue6a9 {{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }} \",\n  }}\n/>\n\n## Options\n\n| Name                   |    Type    |    Default     | Description                                                                                                                                                                                                                          |\n| ---------------------- | :--------: | :------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `home_enabled`         | `boolean`  |    `false`     | display the segment in the HOME folder or not                                                                                                                                                                                        |\n| `fetch_version`        | `boolean`  |     `true`     | fetch the zig version (`zig version`)                                                                                                                                                                                                |\n| `cache_duration`       |  `string`  |     `none`     | the duration for which the version will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none`              |\n| `missing_command_text` |  `string`  |                | text to display when the command is missing                                                                                                                                                                                          |\n| `display_mode`         |  `string`  |   `context`    | <ul><li>`always`: the segment is always displayed</li><li>`files`: the segment is only displayed when file `extensions` listed are present</li><li>`context`: displays the segment when the environment or files is active</li></ul> |\n| `version_url_template` |  `string`  |                | a go [text/template][go-text-template] [template][templates] that creates the URL of the version info / release notes                                                                                                                |\n| `extensions`           | `[]string` | `*.zig, *.zon` | allows to override the default list of file extensions to validate                                                                                                                                                                   |\n| `folders`              | `[]string` |                | allows to override the list of folder names to validate                                                                                                                                                                              |\n| `tooling`              | `[]string` |     `zig`      | the tooling to use for fetching the version                                                                                                                                                                                          |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ if .Error }}{{ .Error }}{{ else }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                           |\n| ---------------- | -------- | ----------------------------------------------------- |\n| `.Full`          | `string` | the full version                                      |\n| `.Major`         | `string` | major number                                          |\n| `.Minor`         | `string` | minor number                                          |\n| `.Patch`         | `string` | patch number                                          |\n| `.Prerelease`    | `string` | prerelease identifier                                 |\n| `.BuildMetadata` | `string` | build identifier                                      |\n| `.URL`           | `string` | URL of the version info / release notes               |\n| `.InProjectDir`  | `bool`   | whether the working directory is within a Zig project |\n| `.Error`         | `string` | error encountered when fetching the version string    |\n\n[go-text-template]: https://golang.org/pkg/text/template/\n[templates]: /docs/configuration/templates\n[zig]: https://ziglang.org/\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/music/lastfm.mdx",
    "content": "---\nid: lastfm\ntitle: LastFM\nsidebar_label: LastFM\n---\n\n## What\n\nShow the currently playing song from a [LastFM][lastfm] user.\n\n:::caution\nBe aware that LastFM updates may be severely delayed when paused and songs may linger in the \"now playing\" state for a prolonged time.\n\nAdditionally, we are using HTTP requests to get the data,\nso you may need to adjust the `http_timeout` to your liking to get better results.\n\nYou **must** request an [API key][api-key] at the LastFM website.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"p:sky\",\n    foreground: \"p:white\",\n    powerline_symbol: \"\\ue0b0\",\n    options: {\n      api_key: \"<YOUR_API_KEY>\",\n      username: \"<LASTFM_USERNAME>\",\n      http_timeout: 20000,\n    },\n    style: \"powerline\",\n    template: ' {{ .Icon }}{{ if ne .Status \"stopped\" }}{{ .Full }}{{ end }} ',\n    type: \"lastfm\",\n  }}\n/>\n\n## Options\n\n| Name           |          Type           |  Default  | Description                                    |\n| -------------- | :---------------------: | :-------: | ---------------------------------------------- |\n| `playing_icon` |        `string`         | `\\uE602 ` | text/icon to show when playing                 |\n| `stopped_icon` |        `string`         | `\\uF04D ` | text/icon to show when stopped                 |\n| `api_key`      | [`template`][templates] |    `.`    | your LastFM [API key][api-key]                 |\n| `username`     |        `string`         |    `.`    | your LastFM username                           |\n| `http_timeout` |          `int`          |   `20`    | in milliseconds - the timeout for http request |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Full }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name      | Type     | Description                                    |\n| --------- | -------- | ---------------------------------------------- |\n| `.Status` | `string` | player status (`playing`, `paused`, `stopped`) |\n| `.Artist` | `string` | current artist                                 |\n| `.Track`  | `string` | current track                                  |\n| `.Full`   | `string` | will output `Artist - Track`                   |\n| `.Icon`   | `string` | icon (based on `.Status`)                      |\n\n[templates]: configuration/templates.mdx\n[lastfm]: https://www.last.fm\n[api-key]: https://www.last.fm/api/account/create\n"
  },
  {
    "path": "website/docs/segments/music/spotify.mdx",
    "content": "---\nid: spotify\ntitle: Spotify\nsidebar_label: Spotify\n---\n\n## What\n\nShow the currently playing song in the [Spotify][spotify] client.\n\n:::caution\nBe aware this can make the prompt a tad bit slower as it needs to get a response from the Spotify player.\n\nOn _macOS & Linux_, all states are supported (playing/paused/stopped).\n\nOn _Windows/WSL_, **only the playing state is supported** (no information when paused/stopped). It supports\nfetching information from the native Spotify application and Edge PWA.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"spotify\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#1BD760\",\n    options: {\n      playing_icon: \"\\ue602 \",\n      paused_icon: \"\\uf04c \",\n      stopped_icon: \"\\uf04d \"\n    }\n  }}\n/>\n\n## Options\n\n| Name           |   Type   |  Default  | Description                    |\n| -------------- | :------: | :-------: | ------------------------------ |\n| `playing_icon` | `string` | `\\ue602 ` | text/icon to show when playing |\n| `paused_icon`  | `string` | `\\uf04c ` | text/icon to show when paused  |\n| `stopped_icon` | `string` | `\\uf04d ` | text/icon to show when stopped |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name      | Type     | Description                                    |\n| --------- | -------- | ---------------------------------------------- |\n| `.Status` | `string` | player status (`playing`, `paused`, `stopped`) |\n| `.Artist` | `string` | current artist                                 |\n| `.Track`  | `string` | current track                                  |\n| `.Icon`   | `string` | icon (based on `.Status`)                      |\n\n[templates]: /docs/configuration/templates\n[spotify]: https://www.spotify.com\n"
  },
  {
    "path": "website/docs/segments/music/ytm.mdx",
    "content": "---\nid: ytm\ntitle: YouTube Music\nsidebar_label: YouTube Music\n---\n\n## What\n\nShows the currently playing song in the [YouTube Music Desktop App][ytmdesktop].\n\n## Setup\n\nYou need to enable the Companion API in the YouTube Music Desktop App settings.\nTo do this, open the app, go to `Settings > Integration` and enable the following:\n\n- Companion server\n- Enable companion authentication\n\nFrom the CLI, run the following command to set the authentication token:\n\n```bash\noh-my-posh auth ytmda\n```\n\nIf done correctly, you should now be able to add the `ytm` segment to your prompt.\n\n:::warning rate limiting\nThe YouTube Music Desktop App has a pretty strict rate limit. Therefore it is recommended\nto set the `cache` property in your configuration. If you don't, the segment will not be able\nto display correctly.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"ytm\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FF0000\",\n    options: {\n      playing_icon: \"\\uf04b \",\n      paused_icon: \"\\uf04c \",\n      stopped_icon: \"\\uf04d \",\n      ad_icon: \"\\ueebb \",\n      http_timeout: 1000\n    },\n    cache: {\n      duration: \"5s\",\n      strategy: \"session\"\n    }\n  }}\n/>\n\n## Options\n\n| Name           |   Type   |  Default  | Description                                        |\n| -------------- | :------: | :-------: | -------------------------------------------------- |\n| `playing_icon` | `string` | `\\uf04b ` | text/icon to show when playing                     |\n| `paused_icon`  | `string` | `\\uf04c ` | text/icon to show when paused                      |\n| `stopped_icon` | `string` | `\\uf04d ` | text/icon to show when stopped                     |\n|   `ad_icon`    | `string` | `\\ueebb ` | text/icon to show when an advertisement is playing |\n| `http_timeout` |  `int`   |  `5000`   | in milliseconds - the timeout for http request     |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Icon }}{{ if ne .Status \\\"stopped\\\" }}{{ .Artist }} - {{ .Track }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name      | Type     | Description                                    |\n| --------- | -------- | ---------------------------------------------- |\n| `.Status` | `string` | player status (`playing`, `paused`, `stopped`) |\n| `.Artist` | `string` | current artist                                 |\n| `.Track`  | `string` | current track                                  |\n| `.Icon`   | `string` | icon (based on `.Status`)                      |\n\n[templates]: /docs/configuration/templates\n[ytmdesktop]: https://github.com/ytmdesktop/ytmdesktop\n"
  },
  {
    "path": "website/docs/segments/scm/fossil.mdx",
    "content": "---\nid: fossil\ntitle: Fossil\nsidebar_label: Fossil\n---\n\n## What\n\nDisplay [Fossil][fossil] information when in a fossil repository.\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"fossil\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#193549\",\n  \"background\": \"#ffeb3b\"\n}}/>\n\n## Options\n\n| Name              |   Type    | Default | Description                                                                                                                                                                                                       |\n| ----------------- | :-------: | :-----: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `native_fallback` | `boolean` | `false` | when set to `true` and `fossil.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `fossil` executable to fetch data. Not all information can be displayed in this case |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue725 {{.Branch}} {{.Status.String}}\n```\n\n:::\n\n### Properties\n\n| Name      | Type           | Description                         |\n| --------- | -------------- | ----------------------------------- |\n| `.Status` | `FossilStatus` | changes in the worktree (see below) |\n| `.Branch` | `string`       | current branch                      |\n\n### FossilStatus\n\n| Name            | Type      | Description                                  |\n| --------------- | --------- | -------------------------------------------- |\n| `.Modified`     | `int`     | number of edited, updated and changed files  |\n| `.Deleted`      | `int`     | number of deleted files                      |\n| `.Added`        | `int`     | number of added files                        |\n| `.Moved`        | `int`     | number of renamed files                      |\n| `.Conflicted`   | `int`     | number of conflicting files                  |\n| `.Changed`      | `boolean` | if the status contains changes or not        |\n| `.HasConflicts` | `boolean` | if the status contains conflicts or not      |\n| `.String`       | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `+`  | added       |\n| `!`  | conflicted  |\n| `-`  | deleted     |\n| `~`  | modified    |\n| `>`  | moved       |\n\n[fossil]: https://fossil-scm.org\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/scm/git.mdx",
    "content": "---\nid: git\ntitle: Git\nsidebar_label: Git\n---\n\n## What\n\nDisplay git information when in a [Git][git] repository. Also works for subfolders. For maximum compatibility,\nmake sure your `git` executable is up-to-date (when branch or status information is incorrect for example).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"git\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    background_templates: [\n      \"{{ if or (.Working.Changed) (.Staging.Changed) }}#FFEB3B{{ end }}\",\n      \"{{ if and (gt .Ahead 0) (gt .Behind 0) }}#FFCC80{{ end }}\",\n      \"{{ if gt .Ahead 0 }}#B388FF{{ end }}\",\n      \"{{ if gt .Behind 0 }}#B388FB{{ end }}\",\n    ],\n    template:\n      \"{{ .UpstreamIcon }}{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}{{ if and (.Working.Changed) (.Staging.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}{{ if gt .StashCount 0 }} \\uf0c7 {{ .StashCount }}{{ end }}\",\n    options: {\n      fetch_status: true,\n      fetch_upstream_icon: true,\n      untracked_modes: {\n        \"/Users/user/Projects/oh-my-posh/\": \"no\",\n      },\n      source: \"cli\",\n      mapped_branches: {\n        \"feat/*\": \"🚀 \",\n        \"bug/*\": \"🐛 \",\n      },\n    },\n  }}\n/>\n\n## Options\n\n### Fetching information\n\nAs doing multiple git calls can slow down the prompt experience, we do not fetch information by default.\nYou can set the following options to `true` to enable fetching additional information (and populate the template).\n\n| Name                  |        Type         | Default | Description                                                                                                                                                                                                                                                                                                                           |\n| --------------------- | :-----------------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `fetch_status`        |      `boolean`      | `false` | fetch the local changes                                                                                                                                                                                                                                                                                                               |\n| `fetch_push_status`   |      `boolean`      | `false` | fetch the push-remote ahead/behind information. Requires `fetch_status` to be enabled                                                                                                                                                                                                                                                 |\n| `ignore_status`       |     `[]string`      |         | do not fetch status for these repo's. Uses the repo's root folder and same logic as the [exclude_folders][exclude_folders] property                                                                                                                                                                                                   |\n| `fetch_upstream_icon` |      `boolean`      | `false` | fetch upstream icon                                                                                                                                                                                                                                                                                                                   |\n| `fetch_bare_info`     |      `boolean`      | `false` | fetch bare repo info                                                                                                                                                                                                                                                                                                                  |\n| `fetch_user`          |   [`User`](#user)   | `false` | fetch the current configured user for the repository                                                                                                                                                                                                                                                                                  |\n| `untracked_modes`     | `map[string]string` |         | map of repo's where to override the default [untracked files mode][untracked]:<ul><li>`no`</li><li>`normal`</li><li>`all`</li></ul>For example `\"untracked_modes\": { \"/Users/me/repos/repo1\": \"no\" }` - defaults to `normal` for all repo's. If you want to override for all repo's, use `*` to set the mode instead of the repo path |\n| `ignore_submodules`   | `map[string]string` |         | map of repo's where to change the [--ignore-submodules][submodules] flag (`none`, `untracked`, `dirty` or `all`). For example `\"ignore_submodules\": { \"/Users/me/repos/repo1\": \"all\" }`. If you want to override for all repo's, use `*` to set the mode instead of the repo path                                                     |\n| `native_fallback`     |      `boolean`      | `false` | when set to `true` and `git.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `git` executable to fetch data. Not all information can be displayed in this case                                                                                                                           |\n| `status_formats`      | `map[string]string` |         | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides.                                                                     |\n| `source`              |      `string`       |  `cli`  | <ul><li>`cli`: fetch the information using the git CLI</li><li>`pwsh`: fetch the information from the [posh-git][poshgit] PowerShell Module</li></ul>                                                                                                                                                                                 |\n| `mapped_branches`     |      `object`       |         | custom glyph/text for specific branches. You can use `*` at the end as a wildcard character for matching                                                                                                                                                                                                                              |\n| `branch_template`     |      `string`       |         | a [template][templates] to format that branch name. You can use `{{ .Branch }}` as reference to the original branch name and `{{ .Upstream }}` as reference to the upstream name                                                                                                                                                      |\n| `disable_with_jj`     |      `boolean`      | `false` | disable the git segment in case of a [Jujutsu] collocated repository                                                                                                                                                                                                                                                                  |\n\n### Icons\n\n#### Branch\n\n| Name                    |   Type   | Default  | Description                                                      |\n| ----------------------- | :------: | :------: | ---------------------------------------------------------------- |\n| `branch_icon`           | `string` | `\\uE0A0` | the icon to use in front of the git branch name                  |\n| `branch_identical_icon` | `string` | `\\u2261` | the icon to display when remote and local are identical          |\n| `branch_ahead_icon`     | `string` | `\\u2191` | the icon to display when the local branch is ahead of its remote |\n| `branch_behind_icon`    | `string` | `\\u2193` | the icon to display when the local branch is behind its remote   |\n| `branch_gone_icon`      | `string` | `\\u2262` | the icon to display when there's no remote branch                |\n\n#### HEAD\n\n| Name               |   Type   | Default  | Description                                                      |\n| ------------------ | :------: | :------: | ---------------------------------------------------------------- |\n| `commit_icon`      | `string` | `\\uF417` | icon/text to display before the commit context (detached HEAD)   |\n| `tag_icon`         | `string` | `\\uF412` | icon/text to display before the tag context                      |\n| `rebase_icon`      | `string` | `\\uE728` | icon/text to display before the context when in a rebase         |\n| `cherry_pick_icon` | `string` | `\\uE29B` | icon/text to display before the context when doing a cherry-pick |\n| `revert_icon`      | `string` | `\\uF0E2` | icon/text to display before the context when doing a revert      |\n| `merge_icon`       | `string` | `\\uE727` | icon/text to display before the merge context                    |\n| `no_commits_icon`  | `string` | `\\uF594` | icon/text to display when there are no commits in the repo       |\n\n#### Upstream\n\n| Name                |        Type         | Default  | Description                                                                                                                                                                  |\n| ------------------- | :-----------------: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `github_icon`       |      `string`       | `\\uF408` | icon/text to display when the upstream is GitHub                                                                                                                             |\n| `gitlab_icon`       |      `string`       | `\\uF296` | icon/text to display when the upstream is GitLab                                                                                                                             |\n| `bitbucket_icon`    |      `string`       | `\\uF171` | icon/text to display when the upstream is Bitbucket                                                                                                                          |\n| `azure_devops_icon` |      `string`       | `\\uEBE8` | icon/text to display when the upstream is Azure DevOps                                                                                                                       |\n| `codecommit_icon`   |      `string`       | `\\uF270` | icon/text to display when the upstream is AWS CodeCommit                                                                                                                     |\n| `codeberg_icon`     |      `string`       | `\\uF330` | icon/text to display when the upstream is Codeberg                                                                                                                           |\n| `git_icon`          |      `string`       | `\\uE5FB` | icon/text to display when the upstream is not known/mapped                                                                                                                   |\n| `upstream_icons`    | `map[string]string` |          | a key, value map representing the remote URL (or a part of that URL) and icon to use in case the upstream URL contains the key. These get precedence over the standard icons |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .HEAD }}{{if .BranchStatus }} {{ .BranchStatus }}{{ end }}{{ if .Working.Changed }} \\uF044 {{ .Working.String }}{{ end }}{{ if and (.Staging.Changed) (.Working.Changed) }} |{{ end }}{{ if .Staging.Changed }} \\uF046 {{ .Staging.String }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name              | Type                | Description                                                                                                                      |\n| ----------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------- |\n| `.RepoName`       | `string`            | the repo folder name                                                                                                             |\n| `.Working`        | `Status`            | changes in the worktree (see below)                                                                                              |\n| `.Staging`        | `Status`            | staged changes in the work tree (see below)                                                                                      |\n| `.HEAD`           | `string`            | the current HEAD context (branch/rebase/merge/...)                                                                               |\n| `.Ref`            | `string`            | the current HEAD reference (branch/tag/...)                                                                                      |\n| `.Behind`         | `int`               | commits behind of upstream                                                                                                       |\n| `.Ahead`          | `int`               | commits ahead of upstream                                                                                                        |\n| `.PushBehind`     | `int`               | commits behind of push remote                                                                                                    |\n| `.PushAhead`      | `int`               | commits ahead of push remote                                                                                                     |\n| `.BranchStatus`   | `string`            | the current branch context (ahead/behind string representation)                                                                  |\n| `.Upstream`       | `string`            | the upstream name (remote)                                                                                                       |\n| `.UpstreamGone`   | `boolean`           | whether the upstream is gone (no remote)                                                                                         |\n| `.UpstreamIcon`   | `string`            | the upstream icon (based on the icons above)                                                                                     |\n| `.UpstreamURL`    | `string`            | the upstream URL for use in [hyperlinks][hyperlinks] in templates: `{{ url .UpstreamIcon .UpstreamURL }}`                        |\n| `.RawUpstreamURL` | `string`            | the raw upstream URL (not cleaned up for display)                                                                                |\n| `.Hash`           | `string`            | the full commit hash                                                                                                             |\n| `.ShortHash`      | `string`            | the short commit hash (7 characters)                                                                                             |\n| `.StashCount`     | `int`               | the stash count                                                                                                                  |\n| `.WorktreeCount`  | `int`               | the worktree count                                                                                                               |\n| `.IsWorkTree`     | `boolean`           | if in a worktree repo or not                                                                                                     |\n| `.IsBare`         | `boolean`           | if in a bare repo or not, only set when `fetch_bare_info` is set to `true`                                                       |\n| `.Dir`            | `string`            | the repository's root directory                                                                                                  |\n| `.RelativeDir`    | `string`            | the current directory relative to the root directory                                                                             |\n| `.Kraken`         | `string`            | a link to the current HEAD in [GitKraken][kraken-ref] for use in [hyperlinks][hyperlinks] in templates `{{ url .HEAD .Kraken }}` |\n| `.Commit`         | `Commit`            | HEAD commit information (see below)                                                                                              |\n| `.Detached`       | `boolean`           | true when the head is detached                                                                                                   |\n| `.Merge`          | `boolean`           | true when in a merge                                                                                                             |\n| `.Rebase`         | `Rebase`            | contains the relevant information when in a rebase                                                                               |\n| `.CherryPick`     | `boolean`           | true when in a cherry pick                                                                                                       |\n| `.Revert`         | `boolean`           | true when in a revert                                                                                                            |\n| `.User`           | `User`              | the current configured user (requires `fetch_user` to be enabled)                                                                |\n| `.Remotes`        | `map[string]string` | a map of remote names to their URLs                                                                                              |\n| `.LatestTag`      | `string`            | the latest tag name                                                                                                              |\n\n#### Status\n\n| Name         | Type      | Description                                  |\n| ------------ | --------- | -------------------------------------------- |\n| `.Unmerged`  | `int`     | number of unmerged changes                   |\n| `.Deleted`   | `int`     | number of deleted changes                    |\n| `.Added`     | `int`     | number of added changes                      |\n| `.Modified`  | `int`     | number of modified changes                   |\n| `.Untracked` | `int`     | number of untracked changes                  |\n| `.Changed`   | `boolean` | if the status contains changes or not        |\n| `.String`    | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `x`  | Unmerged    |\n| `-`  | Deleted     |\n| `+`  | Added       |\n| `~`  | Modified    |\n| `?`  | Untracked   |\n\n#### Commit\n\n| Name         | Type        | Description                             |\n| ------------ | ----------- | --------------------------------------- |\n| `.Author`    | `User`      | the author of the commit (see below)    |\n| `.Committer` | `User`      | the committer of the commit (see below) |\n| `.Subject`   | `string`    | the commit subject                      |\n| `.Timestamp` | `time.Time` | the commit timestamp                    |\n| `.Sha`       | `string`    | the commit SHA1                         |\n| `.Refs`      | `Refs`      | the commit references                   |\n\n##### User\n\n| Name     | Type     | Description      |\n| -------- | -------- | ---------------- |\n| `.Name`  | `string` | the user's name  |\n| `.Email` | `string` | the user's email |\n\n##### Refs\n\n| Name       | Type       | Description       |\n| ---------- | ---------- | ----------------- |\n| `.Heads`   | `[]string` | branches          |\n| `.Tags`    | `[]string` | commit's tags     |\n| `.Remotes` | `[]string` | remote references |\n\nAs these are arrays of strings, you can join them using the `join` function:\n\n```template\n{{ join \", \" .Commit.Refs.Tags }}\n```\n\n#### Rebase\n\n| Name       | Type     | Description                      |\n| ---------- | -------- | -------------------------------- |\n| `.Current` | `int`    | the current rebase step          |\n| `.Total`   | `int`    | the total number of rebase steps |\n| `.HEAD`    | `string` | the current HEAD                 |\n| `.Onto`    | `string` | the branch we're rebasing onto   |\n\n## posh-git\n\nIf you want to display the default [posh-git][poshgit] output, **do not** use this segment\nbut add the following snippet after initializing Oh My Posh in your `$PROFILE`:\n\n```powershell\nfunction Set-PoshGitStatus {\n    $global:GitStatus = Get-GitStatus\n    $env:POSH_GIT_STRING = Write-GitStatus -Status $global:GitStatus\n}\nNew-Alias -Name 'Set-PoshContext' -Value 'Set-PoshGitStatus' -Scope Global -Force\n```\n\nYou can then use the `POSH_GIT_STRING` environment variable in a [text segment][text]:\n\n<Config\n  data={{\n    template:\n      \"{{ if .Env.POSH_GIT_STRING }} {{ .Env.POSH_GIT_STRING }} {{ end }}\",\n  }}\n/>\n\n[git]: https://git-scm.com/\n[poshgit]: https://github.com/dahlbyk/posh-git\n[templates]: /docs/configuration/templates\n[hyperlinks]: /docs/configuration/templates#custom\n[untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt\n[submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt\n[kraken-ref]: https://www.gitkraken.com/invite/nQmDPR9D\n[text]: /docs/segments/system/text\n[exclude_folders]: /docs/configuration/segment#include--exclude-folders\n[Jujutsu]: https://www.jj-vcs.dev/\n"
  },
  {
    "path": "website/docs/segments/scm/jujutsu.mdx",
    "content": "---\nid: jujutsu\ntitle: Jujutsu\nsidebar_label: Jujutsu\n---\n\n## What\n\nDisplay [Jujutsu][jujutsu] information when in a Jujutsu repository.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"jujutsu\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    options: {\n      fetch_status: true,\n      ignore_working_copy: false,\n      fetch_ahead_counter: true,\n      ahead_icon: \"\\u21e1\",\n    },\n  }}\n/>\n\n## Options\n\n### Fetching information\n\nAs doing Jujutsu (jj) calls can slow down the prompt experience, we do not fetch information by default.\nSet `status_formats` to `true` to enable fetching additional information (and populate the template).\n\n| Name                  |        Type         | Default  | Description                                                                                                                                                                                                                                                      |\n| --------------------- | :-----------------: | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `change_id_min_len`   |        `int`        |   `0`    | `ChangeID` will be at least this many characters, even if a shorter one would be unique                                                                                                                                                                          |\n| `fetch_status`        |      `boolean`      | `false`  | fetch the local changes                                                                                                                                                                                                                                          |\n| `ignore_working_copy` |      `boolean`      |  `true`  | don't snapshot/update the working copy                                                                                                                                                                                                                           |\n| `fetch_ahead_counter` |      `boolean`      | `false`  | fetch a counter for number of changes between working copy and closest bookmark                                                                                                                                                                                  |\n| `ahead_icon`          |      `string`       | `\\u21e1` | icon/character between bookmark and ahead counter                                                                                                                                                                                                                |\n| `native_fallback`     |      `boolean`      | `false`  | when set to `true` and `jj.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `jj` executable to fetch data. Not all information can be displayed in this case                                                        |\n| `status_formats`      | `map[string]string` |          | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\uf1fa{{.ChangeID}}{{if .Working.Changed}} \\uf044 {{ .Working.String }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name                | Type     | Description                                                                                  |\n| ------------------- | -------- | -------------------------------------------------------------------------------------------- |\n| `.Working`          | `Status` | changes in the working copy (see below)                                                      |\n| `.ChangeID`         | `string` | The shortest unique prefix of the working copy change that's at least change_id_min_len long |\n| `.ClosestBookmarks` | `string` | Closest bookmark(s) on ancestors                                                             |\n\n### Status\n\n| Name        | Type      | Description                                  |\n| ----------- | --------- | -------------------------------------------- |\n| `.Modified` | `int`     | number of modified files                     |\n| `.Deleted`  | `int`     | number of deleted files                      |\n| `.Added`    | `int`     | number of added files                        |\n| `.Moved`    | `int`     | number of renamed files                      |\n| `.Changed`  | `boolean` | if the status contains changes or not        |\n| `.String`   | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `~`  | Modified    |\n| `-`  | Deleted     |\n| `+`  | Added       |\n| `>`  | Moved       |\n\n[jujutsu]: https://www.jj-vcs.dev/\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/scm/mercurial.mdx",
    "content": "---\nid: mercurial\ntitle: Mercurial\nsidebar_label: Mercurial\n---\n\n## What\n\nDisplay [Mercurial][mercurial] information when in a Mercurial repository. For maximum compatibility,\nmake sure your `hg` executable is up-to-date (when branch or status information is incorrect for example).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"mercurial\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    options: {\n      fetch_status: true,\n      native_fallback: false\n    }\n  }}\n/>\n\n## Options\n\n### Fetching information\n\nAs doing Mercurial (hg) calls can slow down the prompt experience, we do not fetch information by default.\nYou can set `fetch_status` to `true` to enable fetching additional information (and populate the template).\n\n| Name              |        Type         | Default | Description                                                                                                                                                                                                                                                      |\n| ----------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `fetch_status`    |      `boolean`      | `false` | fetch the local changes                                                                                                                                                                                                                                          |\n| `native_fallback` |      `boolean`      | `false` | when set to `true` and `hg.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `hg` executable to fetch data. Not all information can be displayed in this case                                                        |\n| `status_formats`  | `map[string]string` |         | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\nhg {{.Branch}} {{if .LocalCommitNumber}}({{.LocalCommitNumber}}:{{.ChangeSetIDShort}}){{end}}{{range .Bookmarks }} \\uf02e {{.}}{{end}}{{range .Tags}} \\uf02b {{.}}{{end}}{{if .Working.Changed}} \\uf044 {{ .Working.String }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name                | Type       | Description                               |\n| ------------------- | ---------- | ----------------------------------------- |\n| `.Working`          | `Status`   | changes in the worktree (see below)       |\n| `.IsTip`            | `boolean`  | Current commit is the tip commit          |\n| `.ChangeSetID`      | `string`   | The current local commit number           |\n| `.ChangeSetIDShort` | `string`   | The current local commit number           |\n| `.Branch`           | `string`   | current branch                            |\n| `.Bookmarks`        | `[]string` | the currently checked out revision number |\n| `.Tags`             | `[]string` | the currently checked out revision number |\n\n### Status\n\n| Name         | Type      | Description                                  |\n| ------------ | --------- | -------------------------------------------- |\n| `.Untracked` | `int`     | number of files not under version control    |\n| `.Modified`  | `int`     | number of modified files                     |\n| `.Deleted`   | `int`     | number of deleted files                      |\n| `.Added`     | `int`     | number of added files                        |\n| `.Changed`   | `boolean` | if the status contains changes or not        |\n| `.String`    | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `?`  | Untracked   |\n| `~`  | Modified    |\n| `-`  | Deleted     |\n| `+`  | Added       |\n\n[mercurial]: https://www.mercurial-scm.org\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/scm/plastic.mdx",
    "content": "---\nid: plastic\ntitle: Plastic SCM\nsidebar_label: Plastic SCM\n---\n\n## What\n\nDisplay [Plastic SCM][plastic-scm] information when in a plastic repository. Also works for subfolders.\nFor maximum compatibility, make sure your `cm` executable is up-to-date\n(when branch or status information is incorrect for example).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"plastic\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    background_templates: [\n      \"{{ if .MergePending }}#006060{{ end }}\",\n      \"{{ if .Changed }}#FF9248{{ end }}\",\n      \"{{ if and .Changed .Behind }}#ff4500{{ end }}\",\n      \"{{ if .Behind }}#B388FF{{ end }}\",\n    ],\n    template:\n      \"{{ .Selector }}{{ if .Status.Changed }} \\uF044 {{ end }}{{ .Status.String }}\",\n    options: {\n      fetch_status: true,\n    },\n  }}\n/>\n\n## Plastic SCM Icon\n\nIf you want to use the icon of Plastic SCM in the segment, then please help me push the icon in this [issue][fa-issue]\nby leaving a like!\n![icon](https://www.plasticscm.com/images/icon-logo-plasticscm.svg)\n\n## Options\n\n### Fetching information\n\nAs doing multiple `cm` calls can slow down the prompt experience, we do not fetch information by default.\nYou can set the following property to `true` to enable fetching additional information (and populate the template).\n\n| Name              |        Type         | Default | Description                                                                                                                                                                                                                                                      |\n| ----------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `fetch_status`    |      `boolean`      | `false` | fetch the local changes                                                                                                                                                                                                                                          |\n| `native_fallback` |      `boolean`      | `false` | when set to `true` and `cm.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `cm` executable to fetch data. Not all information can be displayed in this case                                                        |\n| `status_formats`  | `map[string]string` |         | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |\n\n### Icons\n\n#### Branch\n\n| Name              |   Type   | Default  | Description                                                                                                              |\n| ----------------- | :------: | :------: | ------------------------------------------------------------------------------------------------------------------------ |\n| `branch_icon`     | `string` | `\\uE0A0` | the icon to use in front of the git branch name                                                                          |\n| `mapped_branches` | `object` |          | custom glyph/text for specific branches. You can use `*` at the end as a wildcard character for matching                 |\n| `branch_template` | `string` |          | a [template][templates] to format that branch name. You can use `{{ .Branch }}` as reference to the original branch name |\n\n#### Selector\n\n| Name          |   Type   | Default  | Description                                                    |\n| ------------- | :------: | :------: | -------------------------------------------------------------- |\n| `commit_icon` | `string` | `\\uF417` | icon/text to display before the commit context (detached HEAD) |\n| `tag_icon`    | `string` | `\\uF412` | icon/text to display before the tag context                    |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Selector }}\n```\n\n:::\n\n### Properties\n\n| Name            | Type     | Description                                                                                                                                                        |\n| --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `.Selector`     | `string` | the current selector context (branch/changeset/label)                                                                                                              |\n| `.Behind`       | `bool`   | the current workspace is behind and changes are incoming                                                                                                           |\n| `.Status`       | `Status` | changes in the workspace (see below)                                                                                                                               |\n| `.MergePending` | `bool`   | if a merge is pending and needs to be committed (known issue: when no file is left after a _Change/Delete conflict_ merge, the `MergePending` property is not set) |\n\n### Status\n\n| Name        | Type      | Description                                  |\n| ----------- | --------- | -------------------------------------------- |\n| `.Unmerged` | `int`     | number of unmerged changes                   |\n| `.Deleted`  | `int`     | number of deleted changes                    |\n| `.Added`    | `int`     | number of added changes                      |\n| `.Modified` | `int`     | number of modified changes                   |\n| `.Moved`    | `int`     | number of moved changes                      |\n| `.Changed`  | `boolean` | if the status contains changes or not        |\n| `.String`   | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `x`  | Unmerged    |\n| `-`  | Deleted     |\n| `+`  | Added       |\n| `~`  | Modified    |\n| `v`  | Moved       |\n\n[templates]: /docs/configuration/templates\n[plastic-scm]: https://www.plasticscm.com/\n[fa-issue]: https://github.com/FortAwesome/Font-Awesome/issues/18504\n"
  },
  {
    "path": "website/docs/segments/scm/sapling.mdx",
    "content": "---\nid: sapling\ntitle: Sapling\nsidebar_label: Sapling\n---\n\n## What\n\nDisplay [Sapling][sapling] information when in a sapling repository.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"sapling\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#4C9642\",\n    background_templates: [\"{{ if .Bookmark }}#4C9642{{ end }}\"],\n    options: {\n      fetch_status: true,\n    },\n  }}\n/>\n\n## Options\n\n### Fetching information\n\n| Name              |        Type         | Default | Description                                                                                                                                                                                                                                                      |\n| ----------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `fetch_status`    |      `boolean`      | `true`  | fetch the local changes - defaults to                                                                                                                                                                                                                            |\n| `native_fallback` |      `boolean`      | `false` | when set to `true` and `sl.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `sl` executable to fetch data. Not all information can be displayed in this case                                                        |\n| `status_formats`  | `map[string]string` |         | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .Bookmark }}\\uf097 {{ .Bookmark }}*{{ else }}\\ue729 {{ .ShortHash }}{{ end }}{{ if .Working.Changed }} \\uf044 {{ .Working.String }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type      | Description                                          |\n| -------------- | --------- | ---------------------------------------------------- |\n| `.RepoName`    | `string`  | the repo folder name                                 |\n| `.Working`     | `Status`  | changes in the worktree (see below)                  |\n| `.Description` | `string`  | the first line of the commit's description           |\n| `.Author`      | `string`  | the author of the commit                             |\n| `.Hash`        | `string`  | the full hash of the commit                          |\n| `.ShortHash`   | `string`  | the short hash of the commit                         |\n| `.When`        | `string`  | the commit's relative time indication                |\n| `.Bookmark`    | `string`  | the commit's bookmark (if any)                       |\n| `.Dir`         | `string`  | the repository's root directory                      |\n| `.RelativeDir` | `string`  | the current directory relative to the root directory |\n| `.New`         | `boolean` | true when there are no commits in the repo           |\n\n### Status\n\n| Name         | Type      | Description                                  |\n| ------------ | --------- | -------------------------------------------- |\n| `.Modified`  | `int`     | number of modified changes                   |\n| `.Added`     | `int`     | number of added changes                      |\n| `.Deleted`   | `int`     | number of removed changes                    |\n| `.Untracked` | `boolean` | number of untracked changes                  |\n| `.Clean`     | `int`     | number of clean changes                      |\n| `.Missing`   | `int`     | number of missing changes                    |\n| `.Ignored`   | `boolean` | number of ignored changes                    |\n| `.String`    | `string`  | a string representation of the changes above |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `~`  | Modified    |\n| `+`  | Added       |\n| `-`  | Deleted     |\n| `?`  | Untracked   |\n| `=`  | Clean       |\n| `!`  | Missing     |\n| `Ø`  | Ignored     |\n\n[sapling]: https://sapling-scm.com/\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/scm/svn.mdx",
    "content": "---\nid: svn\ntitle: Subversion\nsidebar_label: Subversion\n---\n\n## What\n\nDisplay [Subversion][svn] information when in a subversion repository. Also works for subfolders. For maximum compatibility,\nmake sure your `svn` executable is up-to-date (when branch or status information is incorrect for example).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"svn\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    options: {\n      fetch_status: true,\n    },\n  }}\n/>\n\n## Options\n\n### Fetching information\n\nAs doing multiple [subversion][svn] calls can slow down the prompt experience, we do not fetch information by default.\nYou can set the following options to `true` to enable fetching additional information (and populate the template).\n\n| Name              |        Type         | Default | Description                                                                                                                                                                                                                                                      |\n| ----------------- | :-----------------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `fetch_status`    |      `boolean`      | `false` | fetch the local changes                                                                                                                                                                                                                                          |\n| `native_fallback` |      `boolean`      | `false` | when set to `true` and `svn.exe` is not available when inside a WSL2 shared Windows drive, we will fallback to the native `svn` executable to fetch data. Not all information can be displayed in this case                                                      |\n| `status_formats`  | `map[string]string` |         | a key, value map allowing to override how individual status items are displayed. For example, `\"status_formats\": { \"Added\": \"Added: %d\" }` will display the added count as `Added: 1` instead of `+1`. See the [Status](#status) section for available overrides |\n\n:::info\nThe fields `Repo`, `Branch` and `BaseRev` will still work with `fetch_status` set to `false`.\n:::\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\ue0a0{{.Branch}} r{{.BaseRev}} {{.Working.String}}\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description                                                |\n| ---------- | -------- | ---------------------------------------------------------- |\n| `.Working` | `Status` | changes in the worktree (see below)                        |\n| `.Branch`  | `string` | current branch (relative URL reported by `svn info`)       |\n| `.BaseRev` | `int`    | the currently checked out revision number                  |\n| `.Repo`    | `string` | current repository (repos root URL reported by `svn info`) |\n\n### Status\n\n| Name            | Type      | Description                                    |\n| --------------- | --------- | ---------------------------------------------- |\n| `.Untracked`    | `int`     | number of files not under version control      |\n| `.Modified`     | `int`     | number of modified files                       |\n| `.Deleted`      | `int`     | number of deleted files                        |\n| `.Added`        | `int`     | number of added files                          |\n| `.Moved`        | `int`     | number of changed moved files                  |\n| `.Conflicted`   | `int`     | number of changed tracked files with conflicts |\n| `.Changed`      | `boolean` | if the status contains changes or not          |\n| `.HasConflicts` | `boolean` | if the status contains conflicts or not        |\n| `.String`       | `string`  | a string representation of the changes above   |\n\nLocal changes use the following syntax:\n\n| Icon | Description |\n| ---- | ----------- |\n| `?`  | Untracked   |\n| `~`  | Modified    |\n| `-`  | Deleted     |\n| `+`  | Added       |\n| `>`  | Moved       |\n| `!`  | Conflicted  |\n\n[svn]: https://subversion.apache.org\n[templates]: /configuration/templates.mdx\n"
  },
  {
    "path": "website/docs/segments/system/battery.mdx",
    "content": "---\nid: battery\ntitle: Battery\nsidebar_label: Battery\n---\n\n## What\n\n:::caution\nThe segment is not supported and automatically disabled on Windows when WSL 1 is detected. Works fine with WSL 2.\n:::\n\nBattery displays the remaining power percentage for your battery.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"battery\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    background_templates: [\n      '{{if eq \"Charging\" .State.String}}#40c4ff{{end}}',\n      '{{if eq \"Discharging\" .State.String}}#ff5722{{end}}',\n      '{{if eq \"Full\" .State.String}}#4caf50{{end}}',\n    ],\n    template:\n      \" {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}\\uF295 \",\n    options: {\n      discharging_icon: \"\\uE231 \",\n      charging_icon: \"\\uE234 \",\n      charged_icon: \"\\uE22F \",\n    },\n  }}\n/>\n\n## Options\n\n| Name                |   Type    | Default | Description                                                             |\n| ------------------- | :-------: | :-----: | ----------------------------------------------------------------------- |\n| `display_error`     | `boolean` | `false` | show the error context when failing to retrieve the battery information |\n| `charging_icon`     | `string`  |         | icon to display when charging                                           |\n| `discharging_icon`  | `string`  |         | icon to display when discharging                                        |\n| `charged_icon`      | `string`  |         | icon to display when fully charged                                      |\n| `not_charging_icon` | `string`  |         | icon to display when fully charged                                      |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if not .Error }}{{ .Icon }}{{ .Percentage }}{{ end }}{{ .Error }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type      | Description                                                                                                                                                                                                                           |\n| ---------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `.State`         | `struct`  | the battery state, has a `.String` function                                                                                                                                                                                           |\n| `.Current`       | `float64` | Current (momentary) charge rate (in mW).                                                                                                                                                                                              |\n| `.Full`          | `float64` | Last known full capacity (in mWh)                                                                                                                                                                                                     |\n| `.Design`        | `float64` | Reported design capacity (in mWh)                                                                                                                                                                                                     |\n| `.ChargeRate`    | `float64` | Current (momentary) charge rate (in mW). It is always non-negative, consult .State field to check whether it means charging or discharging (on some systems this might be always `0` if the battery doesn't support it)               |\n| `.Voltage`       | `float64` | Current voltage (in V)                                                                                                                                                                                                                |\n| `.DesignVoltage` | `float64` | Design voltage (in V). Some systems (e.g. macOS) do not provide a separate value for this. In such cases, or if getting this fails, but getting `Voltage` succeeds, this field will have the same value as `Voltage`, for convenience |\n| `.Percentage`    | `float64` | the current battery percentage                                                                                                                                                                                                        |\n| `.Error`         | `string`  | the error in case fetching the battery information failed                                                                                                                                                                             |\n| `.Icon`          | `string`  | the icon based on the battery state                                                                                                                                                                                                   |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/connection.mdx",
    "content": "---\nid: connection\ntitle: Connection\nsidebar_label: Connection\n---\n\n## What\n\nShow details about the currently connected network.\n\n:::info\nCurrently only supports Windows. Pull requests for Darwin and Linux support are welcome :)\n:::\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"connection\",\n  \"style\": \"powerline\",\n  \"background\": \"#8822ee\",\n  \"foreground\": \"#222222\",\n  \"powerline_symbol\": \"\\uE0B0\"\n}}/>\n\n## Options\n\n| Name   | Type     | Default          | Description                                                                                                                                                                                                                                           |\n| ------ | :------: | :--------------: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `type` | `string` | `wifi\\|ethernet` | the type of connection to display. Can be a single value or multiple joined by a pipe <inlineCode>\\|</inlineCode> . The first to resolve is shown. Possible values:<ul><li>`wifi`</li><li>`ethernet`</li><li>`bluetooth`</li><li>`cellular`</li></ul> |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if eq .Type \\\"wifi\\\"}}\\uf1eb{{ else if eq .Type \\\"ethernet\\\"}}\\ueba9{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name    | Type     | Description                                             |\n| ------- | -------- | ------------------------------------------------------- |\n| `.Type` | `string` | the connection type type. Single values of `type` above |\n| `.Name` | `string` | the name of the connection                              |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/executiontime.mdx",
    "content": "---\nid: executiontime\ntitle: Execution Time\nsidebar_label: Execution Time\n---\n\n## What\n\nDisplays the execution time of the previously executed command.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"executiontime\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#8800dd\",\n    template: \" <#fefefe>\\ueba2</> {{ .FormattedMs }} \",\n    options: {\n      threshold: 500,\n      style: \"austin\",\n      always_enabled: true,\n    },\n  }}\n/>\n\n## Options\n\n| Name             |   Type    | Default  | Description                                                     |\n| ---------------- | :-------: | :------: | --------------------------------------------------------------- |\n| `always_enabled` | `boolean` | `false`  | always show the duration                                        |\n| `threshold`      |   `int`   |  `500`   | minimum duration (milliseconds) required to enable this segment |\n| `style`          |  `enum`   | `austin` | one of the available format options                             |\n\n### Style\n\nStyle specifies the format in which the time will be displayed. The table below shows some example times in each option.\n\n| format        | 0.001s         | 2.1s           | 3m2.1s         | 4h3m2.1s         |\n| ------------- | -------------- | -------------- | -------------- | ---------------- |\n| `austin`      | `1ms`          | `2.1s`         | `3m 2.1s`      | `4h 3m 2.1s`     |\n| `roundrock`   | `1ms`          | `2s 100ms`     | `3m 2s 100ms`  | `4h 3m 2s 100ms` |\n| `dallas`      | `0.001`        | `2.1`          | `3:2.1`        | `4:3:2.1`        |\n| `galveston`   | `00:00:00`     | `00:00:02`     | `00:03:02`     | `04:03:02`       |\n| `galvestonms` | `00:00:00:001` | `00:00:02:100` | `00:03:02:100` | `04:03:02:100`   |\n| `houston`     | `00:00:00.001` | `00:00:02.1`   | `00:03:02.1`   | `04:03:02.1`     |\n| `amarillo`    | `0.001s`       | `2.1s`         | `182.1s`       | `14,582.1s`      |\n| `round`       | `1ms`          | `2s`           | `3m 2s`        | `4h 3m`          |\n| `lucky7`      | `    1ms`      | ` 2.00s `      | ` 3m  2s`      | ` 4h  3m`        |\n| `iso8601`     | `PT0S`         | `PT2S`         | `PT3M2S`       | `PT4H3M2S`       |\n| `iso8601ms`   | `PT0.001S`     | `PT2.1S`       | `PT3M2.1S`     | `PT4H3M2.1S`     |\n\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .FormattedMs }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type     | Description                                    |\n| -------------- | -------- | ---------------------------------------------- |\n| `.Ms`          | `number` | the execution time in milliseconds             |\n| `.FormattedMs` | `string` | the formatted value based on the `style` above |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/os.mdx",
    "content": "---\nid: os\ntitle: OS\nsidebar_label: OS\n---\n\n## What\n\nDisplay OS specific info - defaults to Icon.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"os\",\n    style: \"plain\",\n    foreground: \"#26C6DA\",\n    background: \"#546E7A\",\n    template: \" {{ if .WSL }}WSL at {{ end }}{{.Icon}}\\uE0B1\",\n    options: {\n      macos: \"mac\",\n    },\n  }}\n/>\n\n## Options\n\n| Name                  |   Type    |    Default     | Description                                              |\n| --------------------- | :-------: | :------------: | -------------------------------------------------------- |\n| `macos`               | `string`  |    `\\uF179`    | the string to use for macOS                              |\n| `linux`               | `string`  |    `\\uF17C`    | the icon to use for Linux                                |\n| `windows`             | `string`  |    `\\uE62A`    | the icon to use for Windows                              |\n| `display_distro_name` | `boolean` |    `false`     | display the distro name instead of icon for Linux or WSL |\n| `alma`                | `string`  |    `\\uF31D`    | the icon to use for AlmaLinux OS                         |\n| `almalinux`           | `string`  |    `\\uF31D`    | the icon to use for AlmaLinux OS                         |\n| `almalinux9`          | `string`  |    `\\uF31D`    | the icon to use for AlmaLinux OS 9                       |\n| `alpine`              | `string`  |    `\\uF300`    | the icon to use for Alpine Linux                         |\n| `android`             | `string`  |    `\\ue70e`    | the icon to use for Android                              |\n| `aosc`                | `string`  |    `\\uF301`    | the icon to use for AOSC OS                              |\n| `arch`                | `string`  |    `\\uF303`    | the icon to use for Arch Linux                           |\n| `centos`              | `string`  |    `\\uF304`    | the icon to use for CentOS                               |\n| `coreos`              | `string`  |    `\\uF305`    | the icon to use for CoreOS Container Linux               |\n| `debian`              | `string`  |    `\\uF306`    | the icon to use for Debian                               |\n| `deepin`              | `string`  |    `\\uF321`    | the icon to use for deepin                               |\n| `devuan`              | `string`  |    `\\uF307`    | the icon to use for Devuan GNU+Linux                     |\n| `elementary`          | `string`  |    `\\uF309`    | the icon to use for elementary OS                        |\n| `endeavouros`         | `string`  |    `\\uF322`    | the icon to use for EndeavourOS                          |\n| `fedora`              | `string`  |    `\\uF30a`    | the icon to use for Fedora                               |\n| `freebsd`             | `string`  | `\\udb82\\udce0` | the icon to use for FreeBSD                              |\n| `gentoo`              | `string`  |    `\\uF30d`    | the icon to use for Gentoo Linux                         |\n| `kali`                | `string`  |    `\\uf327`    | the icon to use for Kali Linux                           |\n| `mageia`              | `string`  |    `\\uF310`    | the icon to use for Mageia                               |\n| `manjaro`             | `string`  |    `\\uF312`    | the icon to use for Manjaro Linux                        |\n| `mint`                | `string`  | `\\udb82\\udced` | the icon to use for Linux Mint                           |\n| `neon`                | `string`  |    `\\uf331`    | the icon to use for KDE neon                             |\n| `nixos`               | `string`  |    `\\uF313`    | the icon to use for NixOS                                |\n| `opensuse`            | `string`  |    `\\uF314`    | the icon to use for openSUSE                             |\n| `opensuse-tumbleweed` | `string`  |    `\\uF314`    | the icon to use for openSUSE Tumbleweed                  |\n| `raspbian`            | `string`  |    `\\uF315`    | the icon to use for Raspberry Pi OS (Raspbian)           |\n| `redhat`              | `string`  |    `\\uF316`    | the icon to use for Red Hat Enterprise Linux (RHEL)      |\n| `rocky`               | `string`  |    `\\uF32B`    | the icon to use for Rocky Linux                          |\n| `sabayon`             | `string`  |    `\\uF317`    | the icon to use for Sabayon                              |\n| `slackware`           | `string`  |    `\\uF319`    | the icon to use for Slackware Linux                      |\n| `ubuntu`              | `string`  |    `\\uF31b`    | the icon to use for Ubuntu                               |\n| `void`                | `string`  |    `\\uf32e`    | the icon to use for Void Linux                           |\n| `zorin`               | `string`  |    `\\uf32f`    | the icon to use for Zorin OS                             |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .WSL }}WSL at {{ end }}{{.Icon}}\n```\n\n:::\n\n### Properties\n\n| Name    | Type     | Description |\n| ------- | -------- | ----------- |\n| `.Icon` | `string` | the OS icon |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/path.mdx",
    "content": "---\nid: path\ntitle: Path\nsidebar_label: Path\n---\n\n## What\n\nDisplay the current path.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"path\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#61AFEF\",\n    options: {\n      style: \"folder\",\n      mapped_locations: {\n        \"C:\\\\temp\": \"\\ue799\",\n      },\n    },\n  }}\n/>\n\n## Options\n\n| Name                        |    Type    |  Default   | Description                                                                                                      |\n| --------------------------- | :--------: | :--------: | ---------------------------------------------------------------------------------------------------------------- |\n| `folder_separator_icon`     |  `string`  |    `/`     | the symbol to use as a separator between folders                                                                 |\n| `folder_separator_template` |  `string`  |            | the [template][templates] to use as a separator between folders                                                  |\n| `home_icon`                 |  `string`  |    `~`     | the icon to display when at `$HOME`                                                                              |\n| `folder_icon`               |  `string`  |    `..`    | the icon to use as a folder indication                                                                           |\n| `windows_registry_icon`     |  `string`  |  `\\uF013`  | the icon to display when in the Windows registry                                                                 |\n| `style`                     |   `enum`   | `agnoster` | how to display the current path                                                                                  |\n| `mixed_threshold`           |  `number`  |    `4`     | the maximum length of a path segment that will be displayed when using `Mixed`                                   |\n| `max_depth`                 |  `number`  |    `1`     | maximum path depth to display before shortening when using `agnoster_short`                                      |\n| `max_width`                 |   `any`    |    `0`     | maximum path length to display when using `powerlevel` or `agnoster`, can leverage [templates]                   |\n| `hide_root_location`        | `boolean`  |  `false`   | hides the root location if it doesn't fit in the last `max_depth` folders when using `agnoster_short`            |\n| `cycle`                     | `[]string` |            | a list of color overrides to cycle through to colorize the individual path folders, e.g. `[ \"#ffffff,#111111\" ]` |\n| `cycle_folder_separator`    | `boolean`  |  `false`   | colorize the `folder_separator_icon` as well when using a cycle                                                  |\n| `folder_format`             |  `string`  |    `%s`    | format to use on individual path folders                                                                         |\n| `edge_format`               |  `string`  |    `%s`    | format to use on the first and last folder of the path                                                           |\n| `left_format`               |  `string`  |    `%s`    | format to use on the first folder of the path - defaults to `edge_format`                                        |\n| `right_format`              |  `string`  |    `%s`    | format to use on the last folder of the path - defaults to `edge_format`                                         |\n| `gitdir_format`             |  `string`  |            | format to use for a git root directory                                                                           |\n| `display_cygpath`           | `boolean`  |  `false`   | display the Cygwin style path using `cygpath -u $PWD`                                                            |\n| `display_root`              | `boolean`  |  `false`   | display the root `/` on Unix systems                                                                             |\n| `dir_length`                |  `number`  |    `1`     | the length of the directory name to display when using `fish`                                                    |\n| `full_length_dirs`          |  `number`  |    `1`     | indicates how many full length directory names should be displayed when using `fish`                             |\n\n## Mapped Locations\n\nAllows you to override a location with an icon/string.\nIt validates if the current path **starts with the specific elements** and replaces it with the icon/string if there's a match.\nTo avoid issues with nested overrides, Oh My Posh will sort the list of mapped locations before doing a replacement.\n\n| Name                       |   Type    | Default | Description                                                                              |\n| -------------------------- | :-------: | :-----: | ---------------------------------------------------------------------------------------- |\n| `mapped_locations_enabled` | `boolean` | `true`  | replace known locations in the path with the replacements before applying the style      |\n| `mapped_locations`         | `object`  |         | custom glyph/text for specific paths. Works regardless of the `mapped_locations_enabled` |\n\nsetting.\n\nFor example, to swap out `C:\\Users\\Leet\\GitHub` with a GitHub icon, you can do the following:\n\n<Config\n  data={{\n    mapped_locations: {\n      \"C:\\\\Users\\\\Leet\\\\GitHub\": \"\\uF09B\",\n    },\n  }}\n/>\n\n### How it works\n\n- To make mapped locations work cross-platform, use `/` as the path separator, Oh My Posh will\n  automatically match effective separators based on the running operating system.\n- If you want to match all child directories, you can use `*` as a wildcard, for example:\n  `\"C:/Users/Bill/*\": \"$\"` will turn `C:/Users/Bill/Downloads` into `$/Downloads` but leave `C:/Users/Bill` unchanged.\n- The character `~` at the start of a mapped location will match the user's home directory.\n- The match is _case-insensitive on Windows and macOS_, but case-sensitive on other operating systems. This means that for\n  user Bill, who has a user account `Bill` on Windows and `bill` on Linux, `~/Foo` might match\n  `C:\\Users\\Bill\\Foo` or `C:\\Users\\Bill\\foo` on Windows but only `/home/bill/Foo` on Linux.\n\n:::warning\nTo prevent mangling path elements, if you use any text style tags (e.g., `<lightGreen>...</>`) in replacement values,\nyou should avoid using a chevron character (`<`/`>`) in the `folder_separator_icon` property, and vice versa.\n:::\n\n### Using regular expressions\n\nFor more complicated cases, you can use the `re:` prefix to use a regular expression with a capture group for matching.\nThis uses Golang's [regexp] package, so you can use any of the [supported syntax][regexp]. The replacement value will be the first capture group,\nsubsequent groups will be ignored.\n\nFor example, `\"re:(C:/[0-9]+/Foo)\": \"#\"` will match `C:\\123\\Foo\\Bar` and replace it with `#\\Bar`. The path used for matching\nwill always use `/`, regardless of the operating system, allowing cross platform matching.\n\nSame as for standard replacements, the match is case insensitive on Windows and WSL mounted drives, but case-sensitive on\nother operating systems.\n\n## Style\n\nStyle sets the way the path is displayed. Based on previous experience and popular themes, there are 10 flavors.\n\n- `agnoster`\n- `agnoster_full`\n- `agnoster_short`\n- `agnoster_left`\n- `full`\n- `folder`\n- `mixed`\n- `letter`\n- `unique`\n- `powerlevel`\n- `fish`\n\n### Agnoster\n\nRenders each intermediate folder as the `folder_icon` separated by the `folder_separator_icon`.\nThe first and the last (current) folder name are always displayed as-is.\n\n### Agnoster Full\n\nRenders each folder name separated by the `folder_separator_icon`.\n\n### Agnoster Short\n\nWhen more than `max_depth` levels deep, it renders one `folder_icon` (if `hide_root_location` is `false`,\nwhich means the root folder does not count for depth) followed by the names of the last `max_depth` folders,\nseparated by the `folder_separator_icon`.\n\n### Agnoster Left\n\nRenders each folder as the `folder_icon` separated by the `folder_separator_icon`.\nOnly the first folder name and its child are displayed in full.\n\n### Full\n\nDisplay the current working directory as a full string with each folder separated by the `folder_separator_icon`.\n\n### Folder\n\nDisplay the name of the current folder.\n\n### Mixed\n\nWorks like `agnoster`, but for any intermediate folder name that is short enough, it will be displayed as-is.\nThe maximum length for the folders to display is governed by the `mixed_threshold` property.\n\n### Letter\n\nWorks like `agnoster_full`, but will write every folder name using the first letter only, except when the folder name\nstarts with a symbol or icon. Specially, the last (current) folder name is always displayed in full.\n\n- `folder` will be shortened to `f`\n- `.config` will be shortened to `.c`\n- `__pycache__` will be shortened to `__p`\n- `➼ folder` will be shortened to `➼ f`\n\n### Unique\n\nWorks like `letter`, but will make sure every folder name is the shortest unique value.\n\nThe uniqueness refers to the displayed path, so `C:\\dev\\dev\\dev\\development` will be displayed as\n`C\\d\\de\\dev\\development` (instead of `C\\d\\d\\d\\development` for `Letter`). Uniqueness does **not** refer to other\nfolders at the same level, so if `C:\\projectA\\dev` and `C:\\projectB\\dev` exist, then both will be displayed as\n`C\\p\\dev`.\n\n### Powerlevel\n\nWorks like `unique`, but will stop shortening when `max_width` is reached.\n\n### Fish\n\nWorks like `letter`, but will display the first `dir_length` characters of each folder name, except for the last\nnumber of folders specified by `full_length_dirs`, which will be displayed in full. Inspired by the Fish shell PWD.\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Path }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type       | Description                                                                                                                                                            |\n| ------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `.Path`       | `string`   | the current directory (based on the `style` property)                                                                                                                  |\n| `.Parent`     | `string`   | the current directory's parent folder which ends with a path separator (designed for use with style `folder`, it is empty if `.Path` contains only one single element) |\n| `.RootDir`    | `boolean`  | true if we're at the root directory (no parent)                                                                                                                        |\n| `.Location`   | `string`   | the current directory (raw value)                                                                                                                                      |\n| `.StackCount` | `int`      | the stack count                                                                                                                                                        |\n| `.Writable`   | `boolean`  | is the current directory writable by the user or not                                                                                                                   |\n| `.Format`     | `function` | format any path based on the segment's settings (e.g. `{{ .Format .Segments.Git.RelativeDir }}`)                                                                       |\n\n[templates]: /docs/configuration/templates\n[regexp]: https://pkg.go.dev/regexp/syntax\n"
  },
  {
    "path": "website/docs/segments/system/project.mdx",
    "content": "---\nid: project\ntitle: Project\nsidebar_label: Project\n---\n\n## What\n\nDisplay the current version of your project defined in the package file.\n\nSupports:\n\n- Node.js project (`package.json`)\n- Deno project (`deno.json`, `deno.jsonc`)\n- JSR project (`jsr.json`, `jsr.jsonc`)\n- Cargo project (`Cargo.toml`)\n- Python project (`pyproject.toml`, supports metadata defined according to [PEP 621][pep621-standard] or [Poetry][poetry-standard])\n- Mojo project (`mojoproject.toml`)\n- PHP project (`composer.json`)\n- Dart project (`pubspec.yaml`)\n- Any nuspec based project (`*.nuspec`, first file match info is displayed)\n- .NET project (`*.sln`, `*.slnf`, `*.slnx`, `*.csproj`, `*.vbproj` or `*.fsproj`, first file match info is displayed)\n- Julia project (`JuliaProject.toml`, `Project.toml`)\n- PowerShell project (`*.psd1`, first file match info is displayed)\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"project\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#193549\",\n    background: \"#ffeb3b\",\n    template:\n      \" {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\\uf487 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }} \",\n  }}\n/>\n\n## Options\n\n| Name             |   Type    | Default | Description                                                                                                         |\n| ---------------- | :-------: | :-----: | ------------------------------------------------------------------------------------------------------------------- |\n| `always_enabled` | `boolean` | `false` | always show the segment                                                                                             |\n| `<type>_files`   |  `array`  |  `[]`   | override the project's files to validate for. Use the `.Type` values listed below to override (e.g. `dotnet_files`) |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .Error }}{{ .Error }}{{ else }}{{ if .Version }}\\uf487 {{.Version}}{{ end }} {{ if .Name }}{{ .Name }}{{ end }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description                                                                                                                                                                                      |\n| ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `.Type`    | `string` | The type of project:<ul><li>`node`</li><li>`deno`</li><li>`jsr`</li><li>`cargo`</li><li>`python`</li><li>`mojo`</li><li>`php`</li><li>`dart`</li><li>`nuspec`</li><li>`dotnet`</li><li>`julia`</li><li>`powershell`</li></ul> |\n| `.Version` | `string` | The version of your project                                                                                                                                                                      |\n| `.Target`  | `string` | The target framework/language version of your project                                                                                                                                            |\n| `.Name`    | `string` | The name of your project                                                                                                                                                                         |\n| `.Error`   | `string` | The error context when we can't fetch the project info                                                                                                                                           |\n\n[templates]: /docs/configuration/templates\n[pep621-standard]: https://peps.python.org/pep-0621/\n[poetry-standard]: https://python-poetry.org/docs/pyproject/\n"
  },
  {
    "path": "website/docs/segments/system/root.mdx",
    "content": "---\nid: root\ntitle: Root\nsidebar_label: Root\n---\n\n## What\n\nShow when the current user is root or when in an elevated shell (Windows).\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"root\",\n  \"style\": \"powerline\",\n  \"powerline_symbol\": \"\\uE0B0\",\n  \"foreground\": \"#111111\",\n  \"background\": \"#ffff66\",\n  \"template\": \"\\uF0E7\"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n``` template\n \\uF0E7\n```\n\n:::\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/session.mdx",
    "content": "---\nid: session\ntitle: Session\nsidebar_label: Session\n---\n\n## What\n\nShow the current user and host name.\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"session\",\n  \"style\": \"diamond\",\n  \"foreground\": \"#ffffff\",\n  \"background\": \"#c386f1\",\n  \"leading_diamond\": \"\\uE0B6\",\n  \"trailing_diamond\": \"\\uE0B0\",\n  \"template\": \"{{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}\"\n}}/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ if .SSHSession }}\\ueba9 {{ end }}{{ .UserName }}@{{ .HostName }}\n```\n\n:::\n\n### Properties\n\n| Name          | Type      | Description                      |\n| ------------- | --------- | -------------------------------- |\n| `.UserName`   | `string`  | the current user's name          |\n| `.HostName`   | `string`  | the current computer's name      |\n| `.SSHSession` | `boolean` | active SSH session or not        |\n| `.Root`       | `boolean` | are you a root/admin user or not |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/shell.mdx",
    "content": "---\nid: shell\ntitle: Shell\nsidebar_label: Shell\n---\n\n## What\n\nShow the current shell name (zsh, PowerShell, bash, ...).\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"shell\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#0077c2\",\n    options: {\n      mapped_shell_names: {\n        pwsh: \"PS\",\n      },\n    },\n  }}\n/>\n\n## Options\n\n| Name                 |   Type   | Default | Description                                                                   |\n| -------------------- | :------: | :-----: | ----------------------------------------------------------------------------- |\n| `mapped_shell_names` | `object` |         | custom glyph/text to use in place of specified shell names (case-insensitive) |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .Name }}\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description       |\n| ---------- | -------- | ----------------- |\n| `.Name`    | `string` | the shell name    |\n| `.Version` | `string` | the shell version |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/status.mdx",
    "content": "---\nid: status\ntitle: Status Code\nsidebar_label: Status Code\n---\n\n## What\n\nDisplays the last known status code and/or the reason that the last command failed.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"status\",\n    style: \"diamond\",\n    foreground: \"#ffffff\",\n    background: \"#00897b\",\n    background_templates: [\"{{ if .Error }}#e91e63{{ end }}\"],\n    trailing_diamond: \"\\uE0B4\",\n    template: \"<#193549>\\uE0B0</> \\uE23A \",\n    options: {\n      always_enabled: true,\n    },\n  }}\n/>\n\n## Options\n\n| Name               | Type      | Default       | Description                                                          |\n| ------------------ | :-------: | :-----------: | -------------------------------------------------------------------- |\n| `always_enabled`   | `boolean` | `false`       | always show the status                                               |\n| `status_template`  | `string`  | `{{ .Code }}` | [template][status-template] used to render an individual status code |\n| `status_separator` | `string`  | `\\|`          | used to separate multiple statuses when `$PIPESTATUS` is available   |\n\n[colors]: /docs/configuration/colors\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .String }}\n```\n\n:::\n\n### Properties\n\n| Name      | Type      | Description                                                                           |\n| --------- | --------- | ------------------------------------------------------------------------------------- |\n| `.Code`   | `number`  | the last known exit code (command or pipestatus)                                      |\n| `.String` | `string`  | the formatted status codes using `status_template` and `status_separator`             |\n| `.Error`  | `boolean` | true if one of the commands has an error (validates on command status and pipestatus) |\n\n### Status Template\n\nWhen using `status_template`, use `if eq .Code 0` to check for a successful exit code. The `.Error` property\nis used on a global context and will not necessarily indicate that the current validated code is a non-zero value.\n\n```template\n{{ if eq .Code 0 }}\\uf00c{{ else }}\\uf071{{ end }}\n```\n\nIn case you want the reason for the exit code instead of code itself, you can use the `reason` function:\n\n```template\n{{ if eq .Code 0 }}\\uf00c{{ else }}\\uf071 {{ reason .Code }}{{ end }}\n```\n\n[templates]: /docs/configuration/templates\n[status-template]: #status-template\n"
  },
  {
    "path": "website/docs/segments/system/sysinfo.mdx",
    "content": "---\nid: sysinfo\ntitle: System Info\nsidebar_label: System Info\n---\n\n## What\n\nDisplay SysInfo.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"sysinfo\",\n    powerline_symbol: \"\\ue0b0\",\n    foreground: \"#ffffff\",\n    background: \"#8f43f3\",\n    template: \" \\ue266 {{ round .PhysicalPercentUsed .Precision }}% \",\n    options: {\n      precision: 2,\n    },\n    style: \"powerline\",\n  }}\n/>\n\n## Options\n\n| Name        | Type  | Default | Description                             |\n| ----------- | :---: | :-----: | --------------------------------------- |\n| `Precision` | `int` |   `2`   | The precision used for any float values |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ round .PhysicalPercentUsed .Precision }}\n```\n\n:::\n\n### Properties\n\n| Name                       | Type       | Description                                                                                                               |\n| -------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------- |\n| `.PhysicalTotalMemory`     | `int`      | is the total of used physical memory                                                                                      |\n| `.PhysicalAvailableMemory` | `int`      | is the total available physical memory (i.e. the amount immediately available to processes)                               |\n| `.PhysicalFreeMemory`      | `int`      | is the total of free physical memory (i.e. considers memory used by the system for any reason [e.g. caching] as occupied) |\n| `.PhysicalPercentUsed`     | `float64`  | is the percentage of physical memory in usage                                                                             |\n| `.SwapTotalMemory`         | `int`      | is the total of used swap memory                                                                                          |\n| `.SwapFreeMemory`          | `int`      | is the total of free swap memory                                                                                          |\n| `.SwapPercentUsed`         | `float64`  | is the percentage of swap memory in usage                                                                                 |\n| `.Load1`                   | `float64`  | is the current load1 (can be empty on windows)                                                                            |\n| `.Load5`                   | `float64`  | is the current load5 (can be empty on windows)                                                                            |\n| `.Load15`                  | `float64`  | is the current load15 (can be empty on windows)                                                                           |\n| `.Disks`                   | `[]struct` | an array of [IOCountersStat][ioinfo] object, you can use any property it has e.g. `.Disks.disk0.IoTime`                   |\n\n[ioinfo]: https://github.com/shirou/gopsutil/blob/e0ec1b9cda4470db704a862282a396986d7e930c/disk/disk.go#L32\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/text.mdx",
    "content": "---\nid: text\ntitle: Text\nsidebar_label: Text\n---\n\n## What\n\nDisplay text.\n\n## Sample Configuration\n\nimport Config from '@site/src/components/Config.js';\n\n<Config data={{\n  \"type\": \"text\",\n  \"style\": \"plain\",\n  \"foreground\": \"#E06C75\",\n  \"template\": \"\\u276F\"\n}}/>\n\n## Template ([info][templates])\n\n### Properties\n\nText segments have no special options. See ([info][templates]) for globally available options.\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/system/time.mdx",
    "content": "---\nid: time\ntitle: Time\nsidebar_label: Time\n---\n\n## What\n\nShow the current timestamp.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"time\",\n    style: \"plain\",\n    foreground: \"#007ACC\",\n    options: {\n      time_format: \"15:04:05\",\n    },\n  }}\n/>\n\n## Options\n\n| Name          |   Type   |  Default   | Description   |\n| ------------- | :------: | :--------: | ------------- |\n| `time_format` | `string` | `15:04:05` | Format to use |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .CurrentDate | date .Format }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type     | Description                             |\n| -------------- | -------- | --------------------------------------- |\n| `.Format`      | `string` | The time format (set via `time_format`) |\n| `.CurrentDate` | `time`   | The time to display (testing purpose)   |\n\n## Syntax\n\n### Formats\n\nFollows the [golang datetime standard][format]:\n\n| DateTime                                         | Format                                                  |\n| ------------------------------------------------ | ------------------------------------------------------- |\n| **Year**                                         | `06`, `2006`                                            |\n| **Month**                                        | `01`, `1`, `Jan`, `January`                             |\n| **Day**                                          | `02`, `2`, `_2` <sub>(width two, right justified)</sub> |\n| **Weekday**                                      | `Mon`, `Monday`                                         |\n| **Hours**                                        | `03`, `3`, `15`                                         |\n| **Minutes**                                      | `04`, `4`                                               |\n| **Seconds**                                      | `05`, `5`                                               |\n| **ms μs ns**                                     | `.000`, `.000000`, `.000000000`                         |\n| **ms μs ns** <sub>(trailing zeros removed)</sub> | `.999`, `.999999`, `.999999999`                         |\n| **am/pm**                                        | `PM`, `pm`                                              |\n| **Timezone**                                     | `MST`                                                   |\n| **Offset**                                       | `-0700`, `-07`, `-07:00`, `Z0700`, `Z07:00`             |\n\n### Predefined formats\n\nThe following predefined date and timestamp [format constants][format-constants] are also available:\n\n| Name            | Format                                |\n| --------------- | ------------------------------------- |\n| **ANSIC**       | `Mon Jan _2 15:04:05 2006`            |\n| **UnixDate**    | `Mon Jan _2 15:04:05 MST 2006`        |\n| **RubyDate**    | `Mon Jan 02 15:04:05 -0700 2006`      |\n| **RFC822**      | `02 Jan 06 15:04 MST`                 |\n| **RFC822Z**     | `02 Jan 06 15:04 -0700`               |\n| **RFC850**      | `Monday, 02-Jan-06 15:04:05 MST`      |\n| **RFC1123**     | `Mon, 02 Jan 2006 15:04:05 MST`       |\n| **RFC1123Z**    | `Mon, 02 Jan 2006 15:04:05 -0700`     |\n| **RFC3339**     | `2006-01-02T15:04:05Z07:00`           |\n| **RFC3339Nano** | `2006-01-02T15:04:05.999999999Z07:00` |\n| **Kitchen**     | `3:04PM`                              |\n| **Stamp**       | `Jan _2 15:04:05`                     |\n| **StampMilli**  | `Jan _2 15:04:05.000`                 |\n| **StampMicro**  | `Jan _2 15:04:05.000000`              |\n| **StampNano**   | `Jan _2 15:04:05.000000000`           |\n\n## Examples\n\nTo display the time in multiple time zones, using [Sprig's Date Functions][sprig-date]:\n\n```text\n{{ .CurrentDate | date .Format }} {{ dateInZone \"15:04Z\" .CurrentDate \"UTC\" }}\n```\n\n[templates]: /docs/configuration/templates\n[format]: https://yourbasic.org/golang/format-parse-string-time-date-example/\n[format-constants]: https://golang.org/pkg/time/#pkg-constants\n[sprig-date]: https://masterminds.github.io/sprig/date.html\n"
  },
  {
    "path": "website/docs/segments/system/upgrade.mdx",
    "content": "---\nid: upgrade\ntitle: Upgrade notice\nsidebar_label: Upgrade\n---\n\n## What\n\nDisplays when there's an update available for Oh My Posh.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"upgrade\",\n    style: \"plain\",\n    foreground: \"#111111\",\n    background: \"#FFD664\",\n    options: {\n      cache_duration: \"168h\",\n    },\n  }}\n/>\n\n## Options\n\n| Name             |   Type   | Default | Description                                                                                                                                                                                                             |\n| ---------------- | :------: | :-----: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `cache_duration` | `string` | `168h`  | the duration for which the segment will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none` |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\uf019\n```\n\n:::\n\n### Properties\n\n| Name       | Type     | Description                         |\n| ---------- | -------- | ----------------------------------- |\n| `.Current` | `string` | the current version number          |\n| `.Latest`  | `string` | the latest available version number |\n\n[templates]: /docs/configuration/templates\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/system/winget.mdx",
    "content": "---\nid: winget\ntitle: WinGet\nsidebar_label: WinGet\n---\n\n## What\n\nDisplays the number of available [WinGet][winget] package updates. This segment only appears when there are updates available.\n\n:::info\nThis segment is only available on Windows.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"winget\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#0077c2\",\n    template: \" \\uf409 {{ .UpdateCount }} \",\n    cache: {\n      duration: \"24h\",\n      strategy: \"device\",\n    },\n  }}\n/>\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\uf409 {{ .UpdateCount }}\n```\n\n:::\n\n### Properties\n\n| Name           | Type              | Description                                   |\n| -------------- | ----------------- | --------------------------------------------- |\n| `.UpdateCount` | `int`             | the number of packages with available updates |\n| `.Updates`     | `[]WinGetPackage` | array of packages with available updates      |\n\n### WinGetPackage\n\n| Name         | Type     | Description                      |\n| ------------ | -------- | -------------------------------- |\n| `.Name`      | `string` | the package name                 |\n| `.ID`        | `string` | the package ID                   |\n| `.Current`   | `string` | the currently installed version  |\n| `.Available` | `string` | the available version for update |\n\n[templates]: /docs/configuration/templates\n[winget]: https://learn.microsoft.com/windows/package-manager/winget/\n"
  },
  {
    "path": "website/docs/segments/system/winreg.mdx",
    "content": "---\nid: winreg\ntitle: Windows Registry Key Query\nsidebar_label: Windows Registry Key Query\n---\n\n## What\n\nDisplay the content of the requested Windows registry key.\n\nSupported registry key types:\n\n- `SZ` (displayed as string value)\n- `EXPAND_SZ` (displayed as string value)\n- `BINARY` (displayed as string value)\n- `DWORD` (displayed in upper-case 0x hex)\n- `QWORD` (displayed in upper-case 0x hex)\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"winreg\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#444444\",\n    template: \" \\uE62A {{ .Value }}\",\n    options: {\n      path: \"HKLM\\\\software\\\\microsoft\\\\windows nt\\\\currentversion\\\\buildlab\",\n      fallback: \"unknown\",\n    },\n  }}\n/>\n\n## Options\n\n| Name       |   Type   | Default | Description                                                                                                                                      |\n| ---------- | :------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `path`     | `string` |         | registry path to the desired key using backslashes and with a valid root HKEY name. Ending path with \\ will get the (Default) key from that path |\n| `fallback` | `string` |         | the value to fall back to if no entry is found                                                                                                   |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Value }}\n```\n\n:::\n\n### Properties\n\n| Name   | Type     | Description                                         |\n| ------ | -------- | --------------------------------------------------- |\n| .Value | `string` | The result of your query, or fallback if not found. |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/web/brewfather.mdx",
    "content": "---\nid: brewfather\ntitle: Brewfather\nsidebar_label: Brewfather\n---\n\n## What\n\nCalling all brewers! Keep up-to-date with the status of your [Brewfather][brewfather] batch directly in your\ncommandline prompt using the brewfather segment!\n\nYou will need your User ID and API Key as generated in\nBrewfather's Settings screen, enabled with **batches.read** and **recipes.read** scopes.\n\n## Sample Configuration\n\nThis example uses the default segment template to show a rendition of detail appropriate to the status of the batch\n\nAdditionally, the background of the segment will turn red if the latest reading is over 4 hours old - possibly helping indicate\nan issue if, for example there is a Tilt or similar device that is supposed to be logging to Brewfather every 15 minutes.\n\n:::info\nTemperature units are in degrees C and specific gravity is expressed as `X.XXX` values.\n:::\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"brewfather\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#33158A\",\n    background_templates: [\n      '{{ if and (.Reading) (eq .Status \"Fermenting\") (gt .ReadingAge 4) }}#cc1515{{end}}',\n    ],\n    options: {\n      user_id: \"abcdefg123456\",\n      api_key: \"qrstuvw78910\",\n      batch_id: \"hijklmno098765\",\n    },\n  }}\n/>\n\n## Options\n\n| Name           |          Type           | Default | Description                                                                                                                     |\n| -------------- | :---------------------: | :-----: | ------------------------------------------------------------------------------------------------------------------------------- |\n| `user_id`      |        `string`         |         | as provided by Brewfather's Generate API Key screen                                                                             |\n| `api_key`      | [`template`][templates] |         | as provided by Brewfather's Generate API Key screen                                                                             |\n| `batch_id`     |        `string`         |         | Get this by navigating to the desired batch on the brewfather website, the batch id is at the end of the URL in the address bar |\n| `day_icon`     |        `string`         |   `d`   | icon or letter to use to indicate days                                                                                          |\n| `http_timeout` |          `int`          |  `20`   | in milliseconds - How long to wait for the Brewfather service to answer the request                                             |\n\n## Icons\n\nYou can override the icons for temperature trend as used by template property `.TemperatureTrendIcon` with:\n\n| Name                 | Default | Description                |\n| -------------------- | ------- | -------------------------- |\n| `doubleup_icon`      | `↑↑`    | increases of more than 4°C |\n| `singleup_icon`      | `↑`     | increase 2-4°C             |\n| `fortyfiveup_icon`   | `↗`     | increase 0.5-2°C           |\n| `flat_icon`          | `→`     | change less than 0.5°C     |\n| `fortyfivedown_icon` | `↘`     | decrease 0.5-2°C           |\n| `singledown_icon`    | `↓`     | decrease 2-4°C             |\n| `doubledown_icon`    | `↓↓`    | decrease more than 4°C     |\n\nYou can override the default icons for batch status as used by template property `.StatusIcon` with:\n\n| Name                       | Default  |\n| -------------------------- | -------- |\n| `planning_status_icon`     | `\\uF8EA` |\n| `brewing_status_icon`      | `\\uF7DE` |\n| `fermenting_status_icon`   | `\\uF499` |\n| `conditioning_status_icon` | `\\uE372` |\n| `completed_status_icon`    | `\\uF7A5` |\n| `archived_status_icon`     | `\\uF187` |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n{{ .StatusIcon }} {{ if .DaysBottledOrFermented }}{{ .DaysBottledOrFermented }}{{ .DayIcon }} {{ end }}{{ url .Recipe.Name .URL }} {{ printf \\\"%.1f\\\" .MeasuredAbv }}%{{ if and (.Reading) (eq .Status \\\"Fermenting\\\") }} {{ printf \\\"%.3f\\\" .Reading.Gravity }} {{ .Reading.Temperature }}\\u00b0 {{ .TemperatureTrendIcon }}{{ end }}\n```\n\n:::\n\n### Properties\n\n| Name                      | Type     | Description                                                                                      |\n| ------------------------- | -------- | ------------------------------------------------------------------------------------------------ |\n| `.Status`                 | `string` | One of \"Planning\", \"Brewing\", \"Fermenting\", \"Conditioning\", \"Completed\" or \"Archived\"            |\n| `.StatusIcon`             | `string` | Icon representing above stats. Can be overridden with properties shown above                     |\n| `.TemperatureTrendIcon`   | `string` | Icon showing temperature trend based on latest and previous reading                              |\n| `.DaysFermenting`         | `int`    | days since start of fermentation                                                                 |\n| `.DaysBottled`            | `int`    | days since bottled/kegged                                                                        |\n| `.DaysBottledOrFermented` | `int`    | one of the above, chosen automatically based on batch status                                     |\n| `.Recipe.Name`            | `string` | The recipe being brewed in this batch                                                            |\n| `.BatchName`              | `string` | The name of this batch                                                                           |\n| `.BatchNumber`            | `int`    | The number of this batch                                                                         |\n| `.MeasuredAbv`            | `float`  | The ABV for the batch - either estimated from recipe or calculated from entered OG and FG values |\n| `.ReadingAge`             | `int`    | age in hours of most recent reading or -1 if there are no readings available                     |\n\n#### Reading\n\n`.Reading` contains the most recent data from devices or manual entry as visible on the Brewfather's batch Readings graph.\nIf there are no readings available, `.Reading` will be null.\n\n| Name                   | Type     | Description                                |\n| ---------------------- | -------- | ------------------------------------------ |\n| `.Reading.Gravity`     | `float`  | specific gravity (in decimal point format) |\n| `.Reading.Temperature` | `float`  | temperature in °C                          |\n| `.Reading.Time`        | `int`    | unix timestamp of reading                  |\n| `.Reading.Comment`     | `string` | comment attached to this reading           |\n| `.Reading.DeviceType`  | `string` | source of the reading, e.g. \"Tilt\"         |\n| `.Reading.DeviceID`    | `string` | id of the device, e.g. \"PINK\"              |\n\n#### Additional properties\n\n| Name                | Type     | Description                                                           |\n| ------------------- | -------- | --------------------------------------------------------------------- |\n| `.MeasuredOg`       | `float`  | The OG for the batch as manually entered into Brewfather              |\n| `.MeasuredFg`       | `float`  | The FG for the batch as manually entered into Brewfather              |\n| `.BrewDate`         | `int`    | The unix timestamp of the brew day                                    |\n| `.FermentStartDate` | `int`    | The unix timestamp when fermentation was started                      |\n| `.BottlingDate`     | `time`   | The unix timestamp when bottled/kegged                                |\n| `.TemperatureTrend` | `float`  | The difference between the most recent and previous temperature in °C |\n| `.DayIcon`          | `string` | given by \"day_icon\", or \"d\" by default                                |\n\n#### Hyperlink support\n\n| Name   | Type     | Description                                                                                                                                                                        |\n| ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `.URL` | `string` | the URL for the batch in the Brewfather app. You can use this to add a hyperlink to the segment if you are using a terminal that supports it. The default template implements this |\n\n### Advanced Templating\n\nThe built in template will provides key useful information. However, you can use the properties about the batch\nto build your own. For reference, the built-in template looks like this:\n\n<Config\n  data={{\n    template:\n      '{{.StatusIcon}} {{if .DaysBottledOrFermented}}{{.DaysBottledOrFermented}}{{.DayIcon}} {{end}}[{{.Recipe.Name}}]({{.URL}}) {{printf \"%.1f\" .MeasuredAbv}}%{{ if and (.Reading) (eq .Status \"Fermenting\")}}: {{printf \"%.3f\" .Reading.Gravity}} {{.Reading.Temperature}}\\u00b0 {{.TemperatureTrendIcon}}{{end}}',\n  }}\n/>\n\n### Unit conversion\n\nBy default temperature readings are provided in degrees C, gravity readings in decimal Specific Gravity unts (X.XXX).\n\nThe following conversion functions are available to the template to convert to other units:\n\n#### Temperature\n\n| Name            | Description                                                                |\n| --------------- | -------------------------------------------------------------------------- |\n| `.DegCToF`      | input: `float` degrees in C; output `float` degrees in F (1 decimal place) |\n| `.DegCToKelvin` | input: `float` degrees in C; output `float` Kelvin (1 decimal place)       |\n\n#### Gravity\n\n| Name         | Description                                                                |\n| ------------ | -------------------------------------------------------------------------- |\n| `.SGToBrix`  | input `float` SG in x.xxx decimal; output `float` Brix (2 decimal places)  |\n| `.SGToPlato` | input `float` SG in x.xxx decimal; output `float` Plato (2 decimal places) |\n\n_(These use the polynomial conversions from [Wikipedia][wikipedia_gravity_page])_\n\n#### Example\n\n<Config\n  data={{\n    template:\n      \"{{if .Reading}}{{.SGToBrix .Reading.Gravity}}°Bx, {{.DegCToF .Reading.Temperature}}°F{{end}}\",\n  }}\n/>\n\nTo display gravity as SG in XXXX format (e.g. \"1020\" instead of \"1.020\"), use the `mulf` template function\n\n<Config\n  data={{\n    template:\n      \"{{if .Reading}}{{.mulf 1000 .Reading.Gravity}}, {{.DegCToF .Reading.Temperature}}°F{{end}}\",\n  }}\n/>\n\n[templates]: /docs/configuration/templates\n[brewfather]: http://brewfather.app\n[wikipedia_gravity_page]: https://en.wikipedia.org/wiki/Brix#Specific_gravity_2\n"
  },
  {
    "path": "website/docs/segments/web/carbonintensity.mdx",
    "content": "---\nid: carbonintensity\ntitle: Carbon Intensity\nsidebar_label: Carbon Intensity\n---\n\n## What\n\nShows the actual and forecast carbon intensity in gCO2/kWh using data from the [Carbon Intensity API][carbonintensity-api].\n\n:::note\nNote that this segment only provides data for Great Britain at the moment. Support for other countries may become available in the future.\n:::\n\n## Sample Configuration\n\n:::caution\nThe API can be slow. It's recommended to set the `http_timeout` property to a large value (e.g. `5000`).\n:::\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"carbonintensity\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#000000\",\n    background: \"#ffffff\",\n    background_templates: [\n      '{{if eq \"very low\" .Index}}#a3e635{{end}}',\n      '{{if eq \"low\" .Index}}#bef264{{end}}',\n      '{{if eq \"moderate\" .Index}}#fbbf24{{end}}',\n      '{{if eq \"high\" .Index}}#ef4444{{end}}',\n      '{{if eq \"very high\" .Index}}#dc2626{{end}}',\n    ],\n    template:\n      \" CO₂ {{ .Index.Icon }}{{ .Actual.String }} {{ .TrendIcon }} {{ .Forecast.String }} \",\n    options: {\n      http_timeout: 5000,\n    },\n  }}\n/>\n\n## Options\n\n| Name           | Type  | Default | Description                                                                                                                                      |\n| -------------- | :---: | :-----: | ------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `http_timeout` | `int` |  `20`   | Timeout (in milliseconds) for HTTP requests. The default is 20ms, but you may need to set this to as high as 5000ms to handle slow API requests. |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n CO₂ {{ .Index.Icon }}{{ .Actual.String }} {{ .TrendIcon }} {{ .Forecast.String }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type     | Description                                                                                                                                                             |\n| ------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `.Forecast`  | `Number` | The forecast carbon intensity in gCO2/kWh. Equal to `0` if no data is available.                                                                                        |\n| `.Actual`    | `Number` | The actual carbon intensity in gCO2/kWh. Equal to `0` if no data is available.                                                                                          |\n| `.Index`     | `Index`  | A rating of the current carbon intensity. Possible values are `\"very low\"`, `\"low\"`, `\"moderate\"`, `\"high\"`, or `\"very high\"`. Equal to `\"??\"` if no data is available. |\n| `.TrendIcon` | `string` | An icon representation of the predicted trend in carbon intensity based on the Actual and Forecast values. Possible values are `\"↗\"`, `\"↘\"`, or `\"→\"`.                  |\n\n#### Number\n\n| Name      | Type     | Description                        |\n| --------- | -------- | ---------------------------------- |\n| `.String` | `string` | string representation of the value |\n\n#### Index\n\n| Name    | Type     | Description                      |\n| ------- | -------- | -------------------------------- |\n| `.Icon` | `string` | icon representation of the value |\n\n[templates]: /docs/configuration/templates\n[carbonintensity-api]: https://carbon-intensity.github.io/api-definitions\n"
  },
  {
    "path": "website/docs/segments/web/http.mdx",
    "content": "---\nid: http\ntitle: HTTP\nsidebar_label: HTTP\n---\n\n## What\n\nHTTP Request is a simple segment to return any json data from any HTTP call.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"http\",\n    style: \"diamond\",\n    foreground: \"#ffffff\",\n    background: \"#c386f1\",\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\uE0B0\",\n    template: \"{{ .Result }}\",\n    options: {\n      url: \"https://jsonplaceholder.typicode.com/posts/1\",\n      method: \"GET\",\n    },\n  }}\n/>\n\n## Options\n\n| Name     |   Type   | Default | Description                                         |\n| -------- | :------: | :-----: | --------------------------------------------------- |\n| `url`    | `string` |   ``    | The HTTP URL you want to call, supports [templates] |\n| `method` | `string` |  `GET`  | The HTTP method to use, `GET` or `POST`             |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Body }}\n```\n\n:::\n\n### Properties\n\n| Name             | Type     | Description                                               |\n| ---------------- | -------- | --------------------------------------------------------- |\n| `.Body.property` | `string` | Replace `.property` with the property you want to display |\n\n[templates]: /docs/configuration/templates\n"
  },
  {
    "path": "website/docs/segments/web/ipify.mdx",
    "content": "---\nid: ipify\ntitle: Ipify\nsidebar_label: Ipify\n---\n\n## What\n\n[Ipify][ipify] is a simple Public IP Address API, it returns your public IP Address in plain text.\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"ipify\",\n    style: \"diamond\",\n    foreground: \"#ffffff\",\n    background: \"#c386f1\",\n    leading_diamond: \"\\ue0b6\",\n    trailing_diamond: \"\\uE0B0\",\n    template: \"{{ .IP }}\",\n    options: {\n      http_timeout: 1000,\n    },\n  }}\n/>\n\n## Options\n\n| Name             |   Type   |         Default         | Description                                                                                                                                                                                                        |\n| ---------------- | :------: | :---------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `url`            | `string` | `https://api.ipify.org` | The Ipify URL, by default IPv4 is used, use `https://api64.ipify.org` for IPv6                                                                                                                                     |\n| `http_timeout`   |  `int`   |          `20`           | in milliseconds - how long may the segment wait for a response of the ipify API                                                                                                                                    |\n| `cache_duration` | `string` |          `24h`          | the duration for which the IP will be cached. The duration is a string in the format `1h2m3s` and is parsed using the [time.ParseDuration] function from the Go standard library. To disable the cache, use `none` |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .IP }}\n```\n\n:::\n\n### Properties\n\n| Name  | Type     | Description              |\n| ----- | -------- | ------------------------ |\n| `.IP` | `string` | Your external IP address |\n\n[ipify]: https://www.ipify.org/\n[templates]: /docs/configuration/templates\n[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration\n"
  },
  {
    "path": "website/docs/segments/web/nba.mdx",
    "content": "---\nid: nba\ntitle: NBA\nsidebar_label: NBA\n---\n\n## What\n\nThe NBA segment allows you to display the scheduling and score information for your\nfavorite NBA team!\n\n## Sample Configuration\n\nIn order to use the NBA segment, you need to provide a valid team\n[tri-code][tri-code] that you'd\nlike to get data for inside of the configuration. For example, if you'd like\nto get information for the Los Angeles Lakers, you'd need to use the \"LAL\"\ntri-code.\n\nThis example uses \"LAL\" to get information for the Los Angeles Lakers. It also\nsets the foreground and background colors to match the theming for the team.\nIf you are interested in getting information about specific foreground and\nbackground colors you could use for other teams, you can explore some of\nthe color schemes [here][color-schemes].\n\nIt is recommended that you set the HTTP timeout to a higher value than the\nnormal default in case it takes some time to gather the scoreboard information.\nIn this case we have the http_timeout set to 1500.\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    background: \"#e9ac2f\",\n    foreground: \"#8748dc\",\n    leading_diamond: \"\\ue0b6\",\n    style: \"diamond\",\n    trailing_diamond: \"\\ue0b0\",\n    type: \"nba\",\n    options: {\n      team: \"LAL\",\n      http_timeout: 1500,\n    },\n  }}\n/>\n\n## Options\n\n| Name           | Type     | Default | Description                                                                                                                    |\n| -------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ |\n| `team`         | `string` |         | tri-code for the NBA team you want to get data for                                                                             |\n| `days_offset`  | `int`    |   `8`   | how many days in advance you wish to see that information for                                                                  |\n| `http_timeout` | `int`    |   `20`  | How long do you want to wait before you want to see your prompt more than your sugar? I figure a half second is a good default |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n \\udb82\\udc06 {{ .HomeTeam}}{{ if .HasStats }} ({{.HomeTeamWins}}-{{.HomeTeamLosses}}){{ end }}{{ if .Started }}:{{.HomeScore}}{{ end }} vs {{ .AwayTeam}}{{ if .HasStats }} ({{.AwayTeamWins}}-{{.AwayTeamLosses}}){{ end }}{{ if .Started }}:{{.AwayScore}}{{ end }} | {{ if not .Started }}{{.GameDate}} | {{ end }}{{.Time}}\n```\n\n:::\n\n### Properties\n\n| Name              | Type      | Description                                                 |\n| ----------------- | --------- | ----------------------------------------------------------- |\n| `.HomeTeam`       | `string`  | home team for the upcoming game                             |\n| `.AwayTeam`       | `string`  | away team for the upcoming game                             |\n| `.Time`           | `string`  | time (EST) that the upcoming game will start                |\n| `.GameDate`       | `string`  | date the game will happen                                   |\n| `.StartTimeUTC`   | `string`  | time (UTC) the game will start                              |\n| `.GameStatus`     | `integer` | integer, 1 = scheduled, 2 = in progress, 3 = finished       |\n| `.HomeScore`      | `int`     | score of the home team                                      |\n| `.AwayScore`      | `int`     | score of the away team                                      |\n| `.HomeTeamWins`   | `int`     | number of wins the home team currently has for the season   |\n| `.HomeTeamLosses` | `int`     | number of losses the home team currently has for the season |\n| `.AwayTeamWins`   | `int`     | number of wins the away team currently has for the season   |\n| `.AwayTeamLosses` | `int`     | number of losses the away team currently has for the season |\n| `.Started`        | `boolean` | if the game was started or not                              |\n| `.HasStats`       | `boolean` | if the game has game stats or not                           |\n\n[color-schemes]: https://teamcolorcodes.com/nba-team-color-codes/\n[templates]: /docs/configuration/templates\n[tri-code]: https://liaison.reuters.com/tools/sports-team-codes\n"
  },
  {
    "path": "website/docs/segments/web/owm.mdx",
    "content": "---\nid: owm\ntitle: Open Weather Map\nsidebar_label: Open Weather Map\n---\n\n## What\n\nShows the current weather of a given location with [Open Weather Map][owm].\n\n:::caution\nYou **must** request an API key at the [Open Weather Map][owm-price] website.\nThe free tier for _Current weather and forecasts collection_ is sufficient.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"owm\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FF0000\",\n    template: \"{{.Weather}} ({{.Temperature}}{{.UnitIcon}})\",\n    options: {\n      api_key: \"<YOUR_API_KEY>\",\n      location: \"AMSTERDAM,NL\",\n      units: \"metric\",\n      http_timeout: 20,\n    },\n  }}\n/>\n\n## Options\n\n| Name           |          Type           |   Default    | Description                                                                                                                                                                                                                                    |\n| -------------- | :---------------------: | :----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `api_key`      | [`template`][templates] |     `.`      | Your API key from [Open Weather Map][owm].                                                                                                                                                                                                     |\n| `location`     | [`template`][templates] | `De Bilt,NL` | The requested location interpreted only if valid coordinates aren't given. Formatted as \\<City,STATE,COUNTRY_CODE\\>. City name, state code and country code divided by comma. Please, refer to ISO 3166 for the state codes or country codes . |\n| `units`        |        `string`         |  `standard`  | Units of measurement. Available values are standard (kelvin), metric (celsius), and imperial (fahrenheit)                                                                                                                                      |\n| `http_timeout` |          `int`          |     `20`     | in milliseconds, the timeout for http request                                                                                                                                                                                                  |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .Weather }} ({{ .Temperature }}{{ .UnitIcon }})\n```\n\n:::\n\n### Properties\n\n| Name           | Type     | Description                                    |\n| -------------- | -------- | ---------------------------------------------- |\n| `.Weather`     | `string` | the current weather icon                       |\n| `.Temperature` | `int`    | the current temperature                        |\n| `.UnitIcon`    | `string` | the current unit icon(based on units property) |\n| `.URL`         | `string` | the url of the current api call                |\n\n[templates]: /docs/configuration/templates\n[owm]: https://openweathermap.org\n[owm-price]: https://openweathermap.org/price\n"
  },
  {
    "path": "website/docs/segments/web/todoist.mdx",
    "content": "---\nid: todoist\ntitle: Todoist\nsidebar_label: Todoist\n---\n\n## What\n\nDisplays your daily tasks from [Todoist][todoist].\n\n:::caution\nThe segment needs an [API Key][guide] from your Todoist profile for this to work.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"todoist\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#FF0000\",\n    template: \"{{.TaskCount}}\",\n    options: {\n      api_key: \"<YOUR_API_KEY>\",\n      http_timeout: 500,\n    },\n  }}\n/>\n\n## Options\n\n| Name           | Type     | Default | Description                                                                                                                                    |\n| -------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |\n| `api_key`      | `string` | `.`     | Your API Key from [Todoist][todoist]                                                                                                           |\n| `http_timeout` | `int`    | `20`    | The time (_in milliseconds_, `ms`) it takes to consider an http request as **timed-out**. If no segment is shown, try increasing this timeout. |\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ .TaskCount }}\n```\n\n:::\n\n### Properties\n\n| Name         | Type  | Description                   |\n| ------------ | ----- | ----------------------------- |\n| `.TaskCount` | `int` | the number of tasks due today |\n\n[todoist]: https://www.todoist.com/\n[templates]: /docs/configuration/templates\n[guide]: https://www.todoist.com/help/articles/find-your-api-token-Jpzx9IIlB\n"
  },
  {
    "path": "website/docs/segments/web/wakatime.mdx",
    "content": "---\nid: wakatime\ntitle: Wakatime\nsidebar_label: Wakatime\n---\n\n## What\n\nShows the tracked time on [wakatime][wt] of the current day\n\n:::caution\nYou **must** request an API key at the [wakatime][wt] website.\nThe free tier for is sufficient. You'll find the API key in your profile settings page.\n:::\n\n## Sample Configuration\n\nimport Config from \"@site/src/components/Config.js\";\n\n<Config\n  data={{\n    type: \"wakatime\",\n    style: \"powerline\",\n    powerline_symbol: \"\\uE0B0\",\n    foreground: \"#ffffff\",\n    background: \"#007acc\",\n    options: {\n      url: \"https://wakatime.com/api/v1/users/current/summaries?start=today&end=today&api_key=API_KEY\",\n      http_timeout: 500,\n    },\n  }}\n/>\n\n## Options\n\n| Name           |   Type   | Default | Description                                                                                                                                    |\n| -------------- | :------: | :-----: | ---------------------------------------------------------------------------------------------------------------------------------------------- |\n| `url`          | `string` |         | The Wakatime [summaries][wk-summaries] URL, including the API key. Example above.                                                              |\n| `http_timeout` |  `int`   |  `20`   | The time (_in milliseconds_, `ms`) it takes to consider an http request as **timed-out**. If no segment is shown, try increasing this timeout. |\n\n### Dynamic API Key\n\nIf you don't want to include the API key into your configuration, the following modification can be done.\n\n<Config\n  data={{\n    options: {\n      url: \"https://wakatime.com/api/v1/users/current/summaries?start=today&end=today&api_key={{ .Env.WAKATIME_API_KEY }}\",\n      http_timeout: 500,\n    },\n  }}\n/>\n\n:::note\n\n`WAKATIME_API_KEY` is an example, **any name is possible and acceptable** as long as the environment variable exists and contains the API key value.\n\nPlease refer to the [Environment Variable][templates-environment-variables] page for more information.\n\n:::\n\n## Template ([info][templates])\n\n:::note default template\n\n```template\n {{ secondsRound .CumulativeTotal.Seconds }}\n```\n\n:::\n\n### Properties\n\n| Name               | Type       | Description                              |\n| ------------------ | ---------- | ---------------------------------------- |\n| `.CumulativeTotal` | `wtTotals` | object holding total tracked time values |\n\n### wtTotals Properties\n\n| Name       | Type      | Description                                                     |\n| ---------- | --------- | --------------------------------------------------------------- |\n| `.Seconds` | `float64` | a number representing the total tracked time in seconds         |\n| `.Text`    | `string`  | a string with human readable tracked time (eg: \"2 hrs 30 mins\") |\n\n[wt]: https://wakatime.com\n[wk-summaries]: https://wakatime.com/developers#summaries\n[templates]: /docs/configuration/templates\n[templates-environment-variables]: /docs/configuration/templates#environment-variables\n"
  },
  {
    "path": "website/docs/share-theme.md",
    "content": "---\nid: share\ntitle: Share theme\nsidebar_label: 📸 Share theme\n---\n\nYou can export your prompt to an image which you can share online. You have the ability to align\nit correctly and add your name for credits too.\n\n:::caution\nSome glyphs aren't rendered correctly, that's not you but the limitations of the renderer.\nDepending on your config, you might have to tweak the output a little bit.\n:::\n\nThe oh-my-posh executable has the `config export image` command to export your current theme configuration\nto a PNG image file (if no other options are specified this will be the name of the config file, or `prompt.png`).\n\n```powershell\noh-my-posh config export image\n```\n\n## Settings File\n\nThe `--settings` flag allows you to provide a JSON file to customize the exported image. This file lets you\noverride colors, set the author name, and specify the background color.\n\n```json title=\"~/.image.settings.json\"\n{\n  \"colors\": {\n    \"red\": \"#FF6B6B\",\n    \"blue\": \"#4ECDC4\",\n    \"green\": \"#45B7D1\",\n    \"yellow\": \"#FFA07A\",\n    \"magenta\": \"#98D8C8\",\n    \"cyan\": \"#F7DC6F\"\n  },\n  \"fonts\": {\n    \"regular\": \"C:/Users/user/Downloads/BigBlueTerminal/BigBlueTerm437NerdFont-Regular.ttf\",\n    \"bold\": \"C:/Users/user/Downloads/BigBlueTerminal/BigBlueTerm437NerdFont-Regular.ttf\",\n    \"italic\": \"C:/Users/user/Downloads/BigBlueTerminal/BigBlueTerm437NerdFont-Regular.ttf\"\n  },\n  \"author\": \"Your Name\",\n  \"background_color\": \"#282828\",\n  \"cursor\": \"\\udb81\\udde7\"\n}\n```\n\n### Settings Options\n\n<!-- markdownlint-disable MD013 -->\n\n| Name               | Type     | Default   | Description                                                                   |\n| ------------------ | -------- | --------- | ----------------------------------------------------------------------------- |\n| `colors`           | `object` |           | Map of ANSI color names to hex color codes. See [16 ANSI color names][colors] |\n| `author`           | `string` |           | Your name or credit to display on the image                                   |\n| `background_color` | `string` | `#151515` | Hex code for the image background                                             |\n| `fonts`            | `object` |           | Font settings for the image, including regular, bold, and italic styles       |\n| `cursor`           | `string` | `_`       | A custom cursor                                                               |\n\n<!-- markdownlint-enable MD013 -->\n\n### Usage\n\n```powershell\noh-my-posh config export image --settings ~/.image.settings.json\n```\n\nThis will export your prompt image using the custom colors and settings from the file.\n\n[colors]: /docs/configuration/colors#standard-colors\n"
  },
  {
    "path": "website/docs/themes.md",
    "content": "---\nid: themes\ntitle: Themes\nsidebar_label: 🎨 Themes\n---\n\nOh My Posh comes with many themes included out-of-the-box. Below are some screenshots of the more common themes.\nFor the full updated list of themes, [view the themes][themes] in GitHub.\n\nOnce you're ready to swap to a theme, follow the steps described in [💡 Getting started > Customize][installation-customize].\n\nThemes with `minimal` in their names do not require a Nerd Font. Read about [🆎Fonts][fonts] for more information.\n\n[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes\n[fonts]: /docs/installation/fonts\n[installation-customize]: /docs/installation/customize\n\n<!-- Do not change the content below, themes are rendered automatically -->\n"
  },
  {
    "path": "website/docusaurus.config.js",
    "content": "export default {\n  title: 'Oh My Posh',\n  tagline: 'The most customizable and fastest prompt engine for any shell.',\n  url: 'https://ohmyposh.dev',\n  baseUrl: '/',\n  favicon: 'img/favicons.svg',\n  organizationName: 'jandedobbeleer',\n  projectName: 'oh-my-posh',\n  onBrokenLinks: 'ignore',\n  plugins: [\n    './plugins/appinsights'\n  ],\n  stylesheets: [\n    \"https://rsms.me/inter/inter.css\",\n    \"https://fonts.googleapis.com/css2?family=Fira+Code&display=swap\"\n  ],\n  themeConfig: {\n    colorMode: {\n      defaultMode: 'light',\n      disableSwitch: false,\n      respectPrefersColorScheme: true,\n    },\n    prism: {\n      additionalLanguages: ['powershell', 'lua', 'jsstacktrace', 'toml'],\n    },\n    docs: {\n        sidebar: {\n          hideable: true,\n        },\n    },\n    navbar: {\n      title: 'Oh My Posh',\n      logo: {\n        alt: 'Oh My Posh Logo',\n        src: 'img/logo-dark.svg',\n        srcDark: 'img/logo-light.svg',\n      },\n      items: [\n        {\n          to: 'docs',\n          activeBasePath: 'docs',\n          label: 'Docs',\n          position: 'left',\n        },\n        {\n          to: 'blog',\n          label: 'Blog',\n          position: 'left'\n        },\n        {\n          href: 'https://github.com/sponsors/JanDeDobbeleer',\n          label: 'Sponsor',\n          position: 'left',\n        },\n        {\n          href: 'https://swag.ohmyposh.dev',\n          label: 'Swag',\n          position: 'left',\n        },\n        {\n          href: 'https://github.com/jandedobbeleer/oh-my-posh',\n          className: 'header-github-link',\n          'aria-label': 'GitHub repository',\n          position: 'right',\n        },\n        {\n          href: 'https://discord.gg/n7E3DkXssv',\n          className: 'header-discord-link',\n          'aria-label': 'Discord',\n          position: 'right',\n        },\n        {\n          href: 'https://staging.bsky.app/profile/ohmyposh.dev',\n          className: 'header-bluesky-link',\n          'aria-label': 'Bluesky',\n          position: 'right',\n        }\n      ],\n    },\n    footer: {\n      style: 'dark',\n      links: [\n        {\n          title: 'How to',\n          items: [\n            {\n              label: 'Getting started',\n              to: 'docs/',\n            },\n            {\n              label: 'Contributing',\n              to: 'docs/contributing/started',\n            },\n          ],\n        },\n        {\n          title: 'Social',\n          items: [\n            {\n              label: 'GitHub',\n              href: 'https://github.com/jandedobbeleer/oh-my-posh',\n            },\n            {\n              label: 'Discord',\n              href: 'https://discord.gg/n7E3DkXssv',\n            },\n            {\n              label: 'Bluesky',\n              href: 'https://staging.bsky.app/profile/ohmyposh.dev',\n            }\n          ],\n        },\n        {\n          title: 'Links',\n          items: [\n            {\n              label: 'Sponsor',\n              href: 'https://github.com/sponsors/JanDeDobbeleer',\n            },\n            {\n              label: 'Product spotlight',\n              href: 'https://buy.polar.sh/polar_cl_qnmZxboq1IDUJo03mk2Jue6ktqZrCXElnzH2s2xbV2R',\n            },\n            {\n              label: 'Docusaurus',\n              href: 'https://github.com/facebook/docusaurus',\n            },\n            {\n              label: 'Privacy',\n              href: '/privacy',\n            },\n          ],\n        },\n                {\n          title: 'Sponsors',\n          items: [\n            {\n              label: 'Merge Conflict',\n              href: 'https://www.mergeconflict.fm/',\n            },\n          ],\n        },\n      ],\n      copyright: `Copyright © ${new Date().getFullYear()} <a href='https://github.com/sponsors/JanDeDobbeleer' target='_blank'>Jan De Dobbeleer</a> and <a href='/docs/contributors'>contributors</a>.`,\n    },\n    announcementBar: {\n      id: 'support_us',\n      content:\n        'If you\\'re enjoying Oh My Posh, consider becoming a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/sponsors/JanDeDobbeleer\">sponsor</a> to keep the project going strong 💪',\n      backgroundColor: '#2c7ae0',\n      textColor: '#ffffff',\n      isCloseable: false,\n    },\n    appInsights: {\n      instrumentationKey: '51741aa7-e087-4e80-b7b0-0863d467462a',\n    },\n    algolia: {\n      appId: 'XIR4RB3TM1',\n      apiKey: '15c5f4340520612ed98fe21d15882029',\n      indexName: 'ohmyposh',\n    },\n  },\n  presets: [\n    [\n      '@docusaurus/preset-classic',\n      {\n        docs: {\n          sidebarPath: './sidebars.js',\n          editUrl: 'https://github.com/jandedobbeleer/oh-my-posh/edit/main/website/',\n        },\n        theme: {\n          customCss: [\n            './src/css/prism-rose-pine-moon.css',\n            './src/css/custom.css'\n          ],\n        },\n        blog: {\n          onInlineAuthors: 'ignore'\n        },\n      },\n    ],\n  ],\n};\n"
  },
  {
    "path": "website/export_themes.mjs",
    "content": "import { exec } from 'node:child_process';\nimport { promises } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// Configuration constants\nconst CONFIG = {\n  THEMES_CONFIG_DIR: join(__dirname, '../themes'),\n  THEMES_STATIC_DIR: join(__dirname, 'static/img/themes'),\n  OUTPUT_FILE: join(__dirname, 'docs/themes.md'),\n  CONCURRENCY: 8,\n  DEFAULT_BG_COLOR: '#151515',\n  THEME_EXTENSIONS: ['.omp.json', '.omp.toml', '.omp.yaml'],\n  GITHUB_BASE_URL: 'https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes'\n};\n\n/**\n * Theme configuration overrides for specific themes\n */\nconst THEME_CONFIG_OVERRIDES = new Map([\n  ['amro.omp.json', { author: 'AmRo', bgColor: '#1C2029' }],\n  ['chips.omp.json', {\n    author: 'CodexLink | v1.2.4, Single Width (07/11/2023) | https://github.com/CodexLink/chips.omp.json',\n    bgColor: CONFIG.DEFAULT_BG_COLOR\n  }],\n  ['craver.omp.json', { author: 'Nick Craver', bgColor: '#282c34' }],\n  ['hunk.omp.json', { author: 'Paris Qian', bgColor: CONFIG.DEFAULT_BG_COLOR }],\n  ['kushal.omp.json', { author: 'Kushal-Chandar', bgColor: CONFIG.DEFAULT_BG_COLOR }],\n  ['night-owl.omp.json', { author: 'Mr-Vipi', bgColor: '#011627' }],\n  ['quick-term.omp.json', { author: 'SokLay', bgColor: CONFIG.DEFAULT_BG_COLOR }],\n  ['catppuccin.omp.json', { author: 'IrwinJuice', bgColor: '#24273A' }],\n  ['catppuccin_latte.omp.json', { author: 'IrwinJuice', bgColor: '#EFF1F5' }],\n  ['catppuccin_frappe.omp.json', { author: 'IrwinJuice', bgColor: '#303446' }],\n  ['catppuccin_macchiato.omp.json', { author: 'IrwinJuice', bgColor: '#24273A' }],\n  ['catppuccin_mocha.omp.json', { author: 'IrwinJuice', bgColor: '#1E1E2E' }]\n]);\n\n/**\n * Creates a new theme configuration with default values\n * @param {string} author - Theme author name\n * @param {string} bgColor - Background color for theme image\n * @returns {Object} Theme configuration object\n */\nfunction createThemeConfig(author = '', bgColor = CONFIG.DEFAULT_BG_COLOR) {\n  return { author, bgColor };\n}\n\n/**\n * Validates if a file is a valid theme file\n * @param {string} fileName - Name of the file to validate\n * @returns {boolean} True if valid theme file\n */\nfunction isValidTheme(fileName) {\n  return CONFIG.THEME_EXTENSIONS.some((ext) => fileName.endsWith(ext));\n}\n\n/**\n * Extracts theme name from filename by removing the extension\n * @param {string} fileName - Theme file name\n * @returns {string} Theme name without extension\n */\nfunction getThemeNameFromFile(fileName) {\n  const lastDotIndex = fileName.lastIndexOf('.');\n  const secondLastDotIndex = fileName.lastIndexOf('.', lastDotIndex - 1);\n  return fileName.slice(0, secondLastDotIndex);\n}\n\n/**\n * Builds the oh-my-posh command for exporting theme image\n * @param {string} configPath - Path to theme config file\n * @param {string} outputImage - Output image file name\n * @param {Object} config - Theme configuration\n * @returns {string} Complete command string\n */\nfunction buildPoshCommand(configPath, outputImage, config) {\n  const parts = [\n    'oh-my-posh config export image',\n    `--config=${configPath}`,\n    `--output=${outputImage}`,\n    `--background-color=${config.bgColor}`,\n  ];\n\n  if (config.author) {\n    parts.push(`--author=\"${config.author}\"`);\n  }\n\n  return parts.join(' ');\n}\n\n/**\n * Generates markdown content for a theme\n * @param {string} themeName - Name of the theme\n * @param {string} themeFile - Original theme file name\n * @returns {Object} Object containing themeData and link strings\n */\nfunction generateThemeMarkdown(themeName, themeFile) {\n  const themeData = `\n### [${themeName}]\n\n[![${themeName}](/img/themes/${themeName}.png)][${themeName}]\n`;\n\n  const link = `[${themeName}]: ${CONFIG.GITHUB_BASE_URL}/${themeFile} '${themeName}'\\n`;\n\n  return { themeData, link };\n}\n\n/**\n * Async pool implementation for controlled concurrency\n * @param {number} concurrency - Maximum concurrent operations\n * @param {Iterable} iterable - Items to process\n * @param {Function} iteratorFn - Function to apply to each item\n */\nasync function* asyncPool(concurrency, iterable, iteratorFn) {\n  const executing = new Set();\n\n  async function consume() {\n    const [promise, value] = await Promise.race(executing);\n    executing.delete(promise);\n    return value;\n  }\n\n  for (const item of iterable) {\n    const promise = (async () => await iteratorFn(item))().then(\n      value => [promise, value]\n    );\n    executing.add(promise);\n\n    if (executing.size >= concurrency) {\n      yield await consume();\n    }\n  }\n\n  while (executing.size) {\n    yield await consume();\n  }\n}\n\n/**\n * Exports a single theme to image and generates markdown\n * @param {string} themeFile - Theme file name\n * @returns {Object|null} Theme data, link, and original filename, or null if failed\n */\nasync function exportTheme(themeFile) {\n  if (!isValidTheme(themeFile)) {\n    return null;\n  }\n\n  try {\n    const configPath = join(CONFIG.THEMES_CONFIG_DIR, themeFile);\n    const config = THEME_CONFIG_OVERRIDES.get(themeFile) || createThemeConfig();\n    const themeName = getThemeNameFromFile(themeFile);\n    const imageFile = `${themeName}.png`;\n    const outputPath = join(CONFIG.THEMES_STATIC_DIR, imageFile);\n\n    const poshCommand = buildPoshCommand(configPath, outputPath, config);\n    const { stderr } = await execAsync(poshCommand);\n\n    if (stderr) {\n      console.error(`Unable to create image for ${themeFile}: ${stderr}`);\n      return null;\n    }\n\n    console.info(`Exported ${themeFile} to ${outputPath}`);\n\n    const { themeData, link } = generateThemeMarkdown(themeName, themeFile);\n\n    return { themeData, link, fileName: themeFile };\n\n  } catch (error) {\n    console.error(`Error processing theme ${themeFile}:`, error.message);\n    return null;\n  }\n}\n\n/**\n * Ensures required directories exist\n */\nasync function ensureDirectories() {\n  try {\n    await promises.access(CONFIG.THEMES_STATIC_DIR);\n  } catch {\n    await promises.mkdir(CONFIG.THEMES_STATIC_DIR, { recursive: true });\n  }\n}\n\n/**\n * Main execution function\n */\nasync function main() {\n  try {\n    console.log('Starting theme export process...');\n\n    await ensureDirectories();\n\n    const themes = await promises.readdir(CONFIG.THEMES_CONFIG_DIR);\n    const validThemes = themes.filter(isValidTheme);\n\n    console.log(`Found ${validThemes.length} valid themes to process`);\n\n    const resultsMap = new Map();\n\n    for await (const result of asyncPool(CONFIG.CONCURRENCY, validThemes, exportTheme)) {\n      if (result) {\n        // Use the original filename as the key for efficient sorting\n        resultsMap.set(result.fileName, result);\n      }\n    }\n\n    // Sort by filename keys alphabetically\n    const sortedFileNames = Array.from(resultsMap.keys()).sort();\n\n    // Append theme data to the file in sorted order\n    for (const fileName of sortedFileNames) {\n      const result = resultsMap.get(fileName);\n      await promises.appendFile(CONFIG.OUTPUT_FILE, result.themeData);\n    }\n\n    // Add separator line\n    await promises.appendFile(CONFIG.OUTPUT_FILE, '\\n');\n\n    // Append all links in the same sorted order\n    for (const fileName of sortedFileNames) {\n      const result = resultsMap.get(fileName);\n      await promises.appendFile(CONFIG.OUTPUT_FILE, result.link);\n    }\n\n    console.log(`Successfully exported ${resultsMap.size} themes to ${CONFIG.OUTPUT_FILE}`);\n\n  } catch (error) {\n    console.error('Export process failed:', error.message);\n    process.exit(1);\n  }\n}\n\n// Execute main function if this file is run directly\n// In ES modules, we check if import.meta.url matches the process argv\nif (process.argv[1] === __filename) {\n  main();\n}\n\nexport {\n  exportTheme,\n  createThemeConfig,\n  isValidTheme,\n  getThemeNameFromFile,\n  generateThemeMarkdown,\n  asyncPool,\n  main,\n};\n"
  },
  {
    "path": "website/package.json",
    "content": "{\n  \"name\": \"website\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"cross-env NODE_ENV=development docusaurus start --poll 1000\",\n    \"build\": \"docusaurus build\",\n    \"serve\": \"docusaurus serve\",\n    \"themes\": \"node export_themes.mjs\",\n    \"clear\": \"docusaurus clear\"\n  },\n  \"dependencies\": {\n    \"@docusaurus/core\": \"^3.9.2\",\n    \"@docusaurus/preset-classic\": \"^3.9.2\",\n    \"@docusaurus/theme-search-algolia\": \"^3.9.2\",\n    \"@mdx-js/react\": \"^3.1.1\",\n    \"classnames\": \"^2.5.1\",\n    \"react\": \"^19.2.3\",\n    \"react-dom\": \"^19.2.3\",\n    \"smol-toml\": \"^1.6.0\",\n    \"yaml\": \"^2.8.2\"\n  },\n  \"devDependencies\": {\n    \"cross-env\": \"^10.1.0\"\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  },\n  \"engines\": {\n    \"npm\": \"10.1.0\",\n    \"node\": \"20.9.0\"\n  },\n  \"volta\": {\n    \"node\": \"20.9.0\"\n  }\n}\n"
  },
  {
    "path": "website/plugins/appinsights/analytics.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nimport ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';\n\nexport default (function () {\n  if (!ExecutionEnvironment.canUseDOM) {\n    return null;\n  }\n\n  return {\n    onRouteUpdate({ location }) {\n      window.setTimeout(() => {\n        if (window.appInsights) {\n          window.appInsights.trackPageView({name: location.pathname});\n        }\n      }, 0);\n    },\n  };\n})();\n"
  },
  {
    "path": "website/plugins/appinsights/index.js",
    "content": "/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nconst { Console } = require('console');\nconst path = require('path');\n\nmodule.exports = function (context) {\n  const { siteConfig } = context;\n  const { themeConfig } = siteConfig;\n  const { appInsights } = themeConfig || {};\n\n  if (!appInsights) {\n    throw new Error(\n      `You need to specify \"appInsights\" object in \"themeConfig\" with \"instrumentationKey\" field in it to use appinsights.`,\n    );\n  }\n\n  const { instrumentationKey } = appInsights;\n\n  if (!instrumentationKey) {\n    throw new Error(\n      'You specified the \"appInsights\" object in \"themeConfig\" but the \"trackingID\" field was missing. ' +\n      'Please ensure this is not a mistake.',\n    );\n  }\n\n  const isProd = process.env.NODE_ENV !== 'development';\n\n  return {\n    name: 'docusaurus-plugin-app-insights',\n\n    getClientModules() {\n      return isProd ? [path.resolve(__dirname, './analytics')] : [];\n    },\n\n    injectHtmlTags() {\n      if (!isProd) {\n        return {};\n      }\n      return {\n        headTags: [\n          {\n            tagName: 'script',\n            attributes: {\n              type: 'text/javascript'\n            },\n            innerHTML: `\n!function(T,l,y){var S=T.location,k=\"script\",D=\"instrumentationKey\",C=\"ingestionendpoint\",I=\"disableExceptionTracking\",E=\"ai.device.\",b=\"toLowerCase\",w=\"crossOrigin\",N=\"POST\",e=\"appInsightsSDK\",t=y.name||\"appInsights\";(y.name||T[e])&&(T[e]=t);var n=T[t]||function(d){var g=!1,f=!1,m={initialize:!0,queue:[],sv:\"5\",version:2,config:d};function v(e,t){var n={},a=\"Browser\";return n[E+\"id\"]=a[b](),n[E+\"type\"]=a,n[\"ai.operation.name\"]=S&&S.pathname||\"_unknown_\",n[\"ai.internal.sdkVersion\"]=\"javascript:snippet_\"+(m.sv||m.version),{time:function(){var e=new Date;function t(e){var t=\"\"+e;return 1===t.length&&(t=\"0\"+t),t}return e.getUTCFullYear()+\"-\"+t(1+e.getUTCMonth())+\"-\"+t(e.getUTCDate())+\"T\"+t(e.getUTCHours())+\":\"+t(e.getUTCMinutes())+\":\"+t(e.getUTCSeconds())+\".\"+((e.getUTCMilliseconds()/1e3).toFixed(3)+\"\").slice(2,5)+\"Z\"}(),iKey:e,name:\"Microsoft.ApplicationInsights.\"+e.replace(/-/g,\"\")+\".\"+t,sampleRate:100,tags:n,data:{baseData:{ver:2}}}}var h=d.url||y.src;if(h){function a(e){var t,n,a,i,r,o,s,c,u,p,l;g=!0,m.queue=[],f||(f=!0,t=h,s=function(){var e={},t=d.connectionString;if(t)for(var n=t.split(\";\"),a=0;a<n.length;a++){var i=n[a].split(\"=\");2===i.length&&(e[i[0][b]()]=i[1])}if(!e[C]){var r=e.endpointsuffix,o=r?e.location:null;e[C]=\"https://\"+(o?o+\".\":\"\")+\"dc.\"+(r||\"services.visualstudio.com\")}return e}(),c=s[D]||d[D]||\"\",u=s[C],p=u?u+\"/v2/track\":d.endpointUrl,(l=[]).push((n=\"SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)\",a=t,i=p,(o=(r=v(c,\"Exception\")).data).baseType=\"ExceptionData\",o.baseData.exceptions=[{typeName:\"SDKLoadFailed\",message:n.replace(/\\./g,\"-\"),hasFullStack:!1,stack:n+\"Snippet failed to load [\"+a+\"] -- Telemetry is disabled Help Link: https://go.microsoft.com/fwlink/?linkid=2128109 Host: \"+(S&&S.pathname||\"_unknown_\")+\" Endpoint: \"+i,parsedStack:[]}],r)),l.push(function(e,t,n,a){var i=v(c,\"Message\"),r=i.data;r.baseType=\"MessageData\";var o=r.baseData;return o.message='AI (Internal): 99 message:\"'+(\"SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) (\"+n+\")\").replace(/\\\"/g,\"\")+'\"',o.properties={endpoint:a},i}(0,0,t,p)),function(e,t){if(JSON){var n=T.fetch;if(n&&!y.useXhr)n(t,{method:N,body:JSON.stringify(e),mode:\"cors\"});else if(XMLHttpRequest){var a=new XMLHttpRequest;a.open(N,t),a.setRequestHeader(\"Content-type\",\"application/json\"),a.send(JSON.stringify(e))}}}(l,p))}function i(e,t){f||setTimeout(function(){!t&&m.core||a()},500)}var e=function(){var n=l.createElement(k);n.src=h;var e=y[w];return!e&&\"\"!==e||\"undefined\"==n[w]||(n[w]=e),n.onload=i,n.onerror=a,n.onreadystatechange=function(e,t){\"loaded\"!==n.readyState&&\"complete\"!==n.readyState||i(0,t)},n}();y.ld<0?l.getElementsByTagName(\"head\")[0].appendChild(e):setTimeout(function(){l.getElementsByTagName(k)[0].parentNode.appendChild(e)},y.ld||0)}try{m.cookie=l.cookie}catch(p){}function t(e){for(;e.length;)!function(t){m[t]=function(){var e=arguments;g||m.queue.push(function(){m[t].apply(m,e)})}}(e.pop())}var n=\"track\",r=\"TrackPage\",o=\"TrackEvent\";t([n+\"Event\",n+\"PageView\",n+\"Exception\",n+\"Trace\",n+\"DependencyData\",n+\"Metric\",n+\"PageViewPerformance\",\"start\"+r,\"stop\"+r,\"start\"+o,\"stop\"+o,\"addTelemetryInitializer\",\"setAuthenticatedUserContext\",\"clearAuthenticatedUserContext\",\"flush\"]),m.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4};var s=(d.extensionConfig||{}).ApplicationInsightsAnalytics||{};if(!0!==d[I]&&!0!==s[I]){var c=\"onerror\";t([\"_\"+c]);var u=T[c];T[c]=function(e,t,n,a,i){var r=u&&u(e,t,n,a,i);return!0!==r&&m[\"_\"+c]({message:e,url:t,lineNumber:n,columnNumber:a,error:i}),r},d.autoExceptionInstrumented=!0}return m}(y.cfg);function a(){y.onInit&&y.onInit(n)}(T[t]=n).queue&&0===n.queue.length?(n.queue.push(a),n.trackPageView({})):a()}(window,document,{\nsrc: \"https://js.monitor.azure.com/scripts/b/ai.2.min.js\", // The SDK URL Source\n// name: \"appInsights\", // Global SDK Instance name defaults to \"appInsights\" when not supplied\n// ld: 0, // Defines the load delay (in ms) before attempting to load the sdk. -1 = block page load and add to head. (default) = 0ms load after timeout,\n// useXhr: 1, // Use XHR instead of fetch to report failures (if available),\ncrossOrigin: \"anonymous\", // When supplied this will add the provided value as the cross origin attribute on the script tag\n// onInit: null, // Once the application insights instance has loaded and initialized this callback function will be called with 1 argument -- the sdk instance (DO NOT ADD anything to the sdk.queue -- As they won't get called)\ncfg: { // Application Insights Configuration\n    instrumentationKey: \"${instrumentationKey}\"\n}});\n             `,\n          },\n        ],\n      };\n    },\n  };\n};\n"
  },
  {
    "path": "website/sidebars.js",
    "content": "export default {\n  docs: [\n    {\n      type: \"category\",\n      label: \"💡 Getting Started\",\n      collapsed: false,\n      items: [\n        {\n          type: \"category\",\n          label: \"📦 Installation\",\n          collapsed: false,\n          items: [\n            \"installation/windows\",\n            \"installation/macos\",\n            \"installation/linux\",\n          ],\n        },\n        \"installation/fonts\",\n        \"installation/prompt\",\n        \"installation/customize\",\n        \"installation/upgrade\",\n      ],\n    },\n    {\n      type: \"category\",\n      label: \"⚙️ Configuration\",\n      link: {\n        type: 'doc',\n        id: 'configuration/introduction',\n      },\n      items: [\n        \"configuration/general\",\n        \"configuration/block\",\n        \"configuration/segment\",\n        \"configuration/title\",\n        \"configuration/colors\",\n        \"configuration/templates\",\n        \"configuration/secondary-prompt\",\n        \"configuration/debug-prompt\",\n        \"configuration/transient\",\n        \"configuration/line-error\",\n        \"configuration/tooltips\",\n        \"configuration/sample\",\n      ],\n    },\n    {\n      type: \"category\",\n      label: \"🌟 Segments\",\n      collapsed: true,\n      items: [\n        {\n          type: \"category\",\n          label: \"🧰 CLI\",\n          collapsed: true,\n          items: [\n            \"segments/cli/angular\",\n            \"segments/cli/argocd\",\n            \"segments/cli/aurelia\",\n            \"segments/cli/bazel\",\n            \"segments/cli/buf\",\n            \"segments/cli/bun\",\n            \"segments/cli/claude\",\n            \"segments/cli/cmake\",\n            \"segments/cli/copilot\",\n            \"segments/cli/deno\",\n            \"segments/cli/docker\",\n            \"segments/cli/firebase\",\n            \"segments/cli/flutter\",\n            \"segments/cli/gitversion\",\n            \"segments/cli/helm\",\n            \"segments/cli/kubectl\",\n            \"segments/cli/mvn\",\n            \"segments/cli/nbgv\",\n            \"segments/cli/nix-shell\",\n            \"segments/cli/npm\",\n            \"segments/cli/nx\",\n            \"segments/cli/pnpm\",\n            \"segments/cli/quasar\",\n            \"segments/cli/react\",\n            \"segments/cli/svelte\",\n            \"segments/cli/talosctl\",\n            \"segments/cli/taskwarrior\",\n            \"segments/cli/tauri\",\n            \"segments/cli/terraform\",\n            \"segments/cli/ui5tooling\",\n            \"segments/cli/umbraco\",\n            \"segments/cli/unity\",\n            \"segments/cli/xmake\",\n            \"segments/cli/yarn\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"☁️ Cloud\",\n          collapsed: true,\n          items: [\n            \"segments/cloud/aws\",\n            \"segments/cloud/az\",\n            \"segments/cloud/azd\",\n            \"segments/cloud/azfunc\",\n            \"segments/cloud/cds\",\n            \"segments/cloud/cf\",\n            \"segments/cloud/cftarget\",\n            \"segments/cloud/gcp\",\n            \"segments/cloud/pulumi\",\n            \"segments/cloud/sitecore\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"🩺 Health\",\n          collapsed: true,\n          items: [\n            \"segments/health/nightscout\",\n            \"segments/health/ramadan\",\n            \"segments/health/strava\",\n            \"segments/health/withings\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"✍️ Languages\",\n          collapsed: true,\n          items: [\n            \"segments/languages/clojure\",\n            \"segments/languages/crystal\",\n            \"segments/languages/dart\",\n            \"segments/languages/dotnet\",\n            \"segments/languages/elixir\",\n            \"segments/languages/fortran\",\n            \"segments/languages/golang\",\n            \"segments/languages/haskell\",\n            \"segments/languages/java\",\n            \"segments/languages/julia\",\n            \"segments/languages/kotlin\",\n            \"segments/languages/lua\",\n            \"segments/languages/mojo\",\n            \"segments/languages/nim\",\n            \"segments/languages/node\",\n            \"segments/languages/ocaml\",\n            \"segments/languages/perl\",\n            \"segments/languages/php\",\n            \"segments/languages/python\",\n            \"segments/languages/r\",\n            \"segments/languages/ruby\",\n            \"segments/languages/rust\",\n            \"segments/languages/swift\",\n            \"segments/languages/v\",\n            \"segments/languages/vala\",\n            \"segments/languages/zig\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"🎧 Music\",\n          collapsed: true,\n          items: [\n            \"segments/music/lastfm\",\n            \"segments/music/spotify\",\n            \"segments/music/ytm\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"🗂️ Source control\",\n          collapsed: true,\n          items: [\n            \"segments/scm/fossil\",\n            \"segments/scm/git\",\n            \"segments/scm/jujutsu\",\n            \"segments/scm/mercurial\",\n            \"segments/scm/plastic\",\n            \"segments/scm/sapling\",\n            \"segments/scm/svn\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"🖥️ System\",\n          collapsed: true,\n          items: [\n            \"segments/system/battery\",\n            \"segments/system/connection\",\n            \"segments/system/executiontime\",\n            \"segments/system/os\",\n            \"segments/system/path\",\n            \"segments/system/project\",\n            \"segments/system/root\",\n            \"segments/system/session\",\n            \"segments/system/shell\",\n            \"segments/system/status\",\n            \"segments/system/sysinfo\",\n            \"segments/system/text\",\n            \"segments/system/time\",\n            \"segments/system/upgrade\",\n            \"segments/system/winget\",\n            \"segments/system/winreg\",\n          ]\n        },\n        {\n          type: \"category\",\n          label: \"🌐 Web\",\n          collapsed: true,\n          items: [\n            \"segments/web/brewfather\",\n            \"segments/web/carbonintensity\",\n            \"segments/web/http\",\n            \"segments/web/ipify\",\n            \"segments/web/nba\",\n            \"segments/web/owm\",\n            \"segments/web/todoist\",\n            \"segments/web/wakatime\",\n          ]\n        },\n      ],\n    },\n    {\n      type: \"category\",\n      label: \"🤝 Contributing\",\n      collapsed: true,\n      items: [\n        \"contributing/started\",\n        \"contributing/segment\",\n        \"contributing/git\",\n        \"contributing/plastic\",\n      ],\n    },\n    \"dsc\",\n    \"themes\",\n    \"share\",\n    {\n      type: \"category\",\n      label: \"🛠️ Advanced\",\n      collapsed: true,\n      items: [\n        \"advanced/mcp-server\",\n      ],\n    },\n    {\n      type: \"category\",\n      label: \"🧪 Experimental\",\n      collapsed: true,\n      items: [\n        \"experimental/streaming\",\n      ],\n    },\n    \"faq\",\n    \"migrating\",\n    \"contributors\",\n  ],\n};\n"
  },
  {
    "path": "website/src/components/Auth.js",
    "content": "import React from 'react';\nimport {useLocation} from '@docusaurus/router';\nimport CodeBlock from '@theme/CodeBlock';\n\nfunction Auth() {\n  const search = useLocation().search;\n  const params = new URLSearchParams(search);\n\n  if (params.get('error')) {\n    let buff = Buffer.from(params.get('error'), 'base64');\n    let text = buff.toString('ascii');\n    return (\n      <div>\n        <p>\n          Error on authenticating with the <code>{params.get('segment')}</code> API, please provide the following error message\n          in a <a href='https://github.com/JanDeDobbeleer/oh-my-posh/issues/new/choose'>ticket</a> in\n          case this was unexpected.\n        </p>\n        <CodeBlock className=\"language-jsstacktrace\">\n          {text}\n        </CodeBlock>\n      </div>\n    );\n  }\n\n  const config = `\n  {\n    \"type\": \"${params.get('segment')}\",\n    ...\n    \"options\": {\n      // highlight-start\n      \"access_token\": \"${params.get('access_token')}\",\n      \"refresh_token\": \"${params.get('refresh_token')}\",\n      \"expires_in\": ${params.get('expires_in')}\n      // highlight-end\n    }\n  }\n  `;\n\n  return (\n    <div>\n      <p>\n        Use the following snippet to adjust your segment and enable the authentication.\n      </p>\n      <CodeBlock className=\"language-json\" title=\"config.omp.json\">\n        {config}\n      </CodeBlock>\n    </div>\n  );\n}\n\nexport default Auth;\n"
  },
  {
    "path": "website/src/components/Config.js",
    "content": "import React from 'react';\nimport CodeBlock from '@theme/CodeBlock';\nimport Tabs from \"@theme/Tabs\";\nimport TabItem from \"@theme/TabItem\";\nimport YAML from 'yaml';\nimport TOML from 'smol-toml';\n\nfunction Config(props) {\n\n  const { data, metastring = { json: \"\", yaml: \"\", toml: \"\" } } = props;\n\n  const patchTomlData = () => {\n    if (data?.properties) {\n      const properties = data.properties;\n      delete data.properties;\n\n      return {\n        ...data,\n        blocks: {\n          segments: {\n            properties: properties\n          }\n        }\n      };\n    }\n\n    return data;\n  };\n\n  return (\n    <Tabs\n        defaultValue=\"json\"\n        groupId=\"sample\"\n        values={[\n          { label: 'json', value: 'json', },\n          { label: 'yaml', value: 'yaml', },\n          { label: 'toml', value: 'toml', },\n        ]\n      }>\n      <TabItem value=\"json\">\n        <CodeBlock language=\"json\" metastring={metastring.json}>\n          {JSON.stringify(data, null, 2)}\n        </CodeBlock>\n      </TabItem>\n      <TabItem value=\"yaml\">\n        <CodeBlock language=\"yaml\" metastring={metastring.yaml}>\n          {YAML.stringify(data)}\n        </CodeBlock>\n      </TabItem>\n      <TabItem value=\"toml\">\n        <CodeBlock language=\"toml\" metastring={metastring.toml}>\n          {TOML.stringify(patchTomlData())}\n        </CodeBlock>\n      </TabItem>\n    </Tabs>\n  );\n}\n\nexport default Config;\n"
  },
  {
    "path": "website/src/css/custom.css",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framework designed to\n * work well for content-centric websites.\n */\n\n/* You can override the default Infima variables here. */\n:root {\n  --ifm-color-primary: #2c7ae0;\n  --ifm-color-primary-dark: rgb(38, 103, 189);\n  --ifm-color-primary-darker: rgb(28, 75, 138);\n  --ifm-color-primary-darkest: rgb(19, 51, 94);\n  --ifm-color-primary-light: rgb(74, 143, 232);\n  --ifm-color-primary-lighter: rgb(95, 157, 237);\n  --ifm-color-primary-lightest: rgb(8, 9, 10);\n  --ifm-code-font-size: 95%;\n  --ifm-pre-background: #232136;\n}\n\n.docusaurus-highlight-code-line {\n  background-color: rgb(72, 77, 91);\n  display: block;\n  margin: 0 calc(-1 * var(--ifm-pre-padding));\n  padding: 0 var(--ifm-pre-padding);\n}\n\n.badge {\n  display: none !important;\n}\n\n.hero {\n  background-color: #173448;\n}\n\n.hero--image {\n  margin-top: 4rem;\n}\n\n.header-github-link:hover {\n  opacity: 0.6;\n}\n\n.header-github-link:before {\n  content: \"\";\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\nhtml[data-theme=\"dark\"] .header-github-link:before {\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n.header-bluesky-link:hover {\n  opacity: 0.6;\n}\n\n.header-bluesky-link:before {\n  content: \"\";\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 568 501' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='%230085ff' d='M123.121 33.664C188.241 82.553 258.281 181.68 284 234.873c25.719-53.192 95.759-152.32 160.879-201.21C491.866-1.611 568-28.906 568 57.947c0 17.346-9.945 145.713-15.778 166.555-20.275 72.453-94.155 90.933-159.875 79.748C507.222 323.8 536.444 388.56 473.333 453.32c-119.86 122.992-172.272-30.859-185.702-70.281-2.462-7.227-3.614-10.608-3.631-7.733-.017-2.875-1.169.506-3.631 7.733-13.43 39.422-65.842 193.273-185.702 70.281-63.111-64.76-33.89-129.52 80.454-149.07-65.72 11.185-139.6-7.295-159.875-79.748C9.945 203.66 0 75.293 0 57.947 0-28.906 76.135-1.611 123.121 33.664z'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n.header-affiliate-link:hover {\n  opacity: 0.6;\n}\n\n.header-affiliate-link:before {\n  content: \"\";\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg fill='black' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' class='css-1hsn8wk'%3E%3Cpath d='M51.0696 4.92194H88.7341C94.8309 4.92194 99.7736 10.0293 99.7736 16.3295V60.6175C99.7736 66.9179 94.8309 72.0252 88.7341 72.0252H34.835L51.0696 4.92194Z' fill='currentColor'%3E%3C/path%3E%3Cpath d='M41.2866 17.6346H10.9455C4.90046 17.6346 0 22.7419 0 29.0421V73.3302C0 79.6305 4.90046 84.7378 10.9455 84.7378H48.2888L49.7863 78.495H26.6878L41.2866 17.6346Z' %3E%3C/path%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\nhtml[data-theme=\"dark\"] .header-affiliate-link:before {\n  background: url(\"data:image/svg+xml,%3Csvg fill='white' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' class='css-1hsn8wk'%3E%3Cpath d='M51.0696 4.92194H88.7341C94.8309 4.92194 99.7736 10.0293 99.7736 16.3295V60.6175C99.7736 66.9179 94.8309 72.0252 88.7341 72.0252H34.835L51.0696 4.92194Z' %3E%3C/path%3E%3Cpath d='M41.2866 17.6346H10.9455C4.90046 17.6346 0 22.7419 0 29.0421V73.3302C0 79.6305 4.90046 84.7378 10.9455 84.7378H48.2888L49.7863 78.495H26.6878L41.2866 17.6346Z' %3E%3C/path%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n.header-discord-link:hover {\n  opacity: 0.6;\n}\n\n.header-discord-link:before {\n  content: \"\";\n  width: 24px;\n  height: 24px;\n  display: flex;\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 127.14 96.36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill%3D%22%235865F2%22 d='M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\nhtml[data-theme=\"dark\"] .header-discord-link:before {\n  background: url(\"data:image/svg+xml,%3Csvg viewBox='0 0 127.14 96.36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill%3D%22%235865F2%22 d='M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z'/%3E%3C/svg%3E\")\n    center / contain no-repeat;\n}\n\n/* Admonition */\n\ndiv.theme-admonition.theme-admonition-tip.alert.alert--success {\n  background-color: #9ccfd8;\n  border-color: #56949f;\n}\n\nhtml[data-theme=\"dark\"] div.theme-admonition.theme-admonition-tip {\n  color: #102445;\n}\n\nhtml[data-theme=\"dark\"] div.theme-admonition.theme-admonition-tip svg {\n  fill: #102445;\n}\n\nhtml[data-theme=\"dark\"] div.theme-admonition.theme-admonition-tip a {\n  color: #102445;\n}\n\niframe.youtube {\n  width: 100%;\n  margin-bottom: 15px;\n}\n\n@media screen and (max-width: 350px) {\n  iframe.youtube {\n    height: 200px;\n  }\n}\n\n@media screen and (min-width: 350px) {\n  iframe.youtube {\n    height: 300px;\n  }\n}\n\n@media screen and (min-width: 600px) {\n  iframe.youtube {\n    height: 400px;\n  }\n}\n\n.winstore {\n  width: 200px;\n  border-radius: 8px;\n  margin-top: 25px;\n}\n\n[data-theme=\"dark\"] .withings {\n  background: white;\n  padding: 17px 10px 10px 10px;\n  display: inline;\n  border-radius: 10px;\n}\n\n[data-theme=\"light\"] .withings {\n  background: black;\n  padding: 17px 10px 10px 10px;\n  display: inline;\n  border-radius: 10px;\n}\n\n.withings svg {\n  width: 150px;\n}\n\n[data-theme=\"light\"] .withings svg path {\n  fill: white;\n}\n\n[data-theme=\"dark\"] .withings svg path {\n  fill: black;\n}\n\nh1.hero__title {\n  color: white;\n}\n\np.hero__subtitle {\n  color: white;\n}\n\na.getStarted_Sjon {\n  color: white;\n}\n\n[data-theme=\"light\"] .themedImage_ToTc {\n  filter: invert(0%) sepia(8%) saturate(2885%) hue-rotate(67deg) brightness(84%)\n    contrast(87%);\n}\n\n[data-theme=\"dark\"] .themedImage_ToTc {\n  filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(226deg)\n    brightness(102%) contrast(101%);\n}\n\n/* Fonts */\n\n@font-face {\n  font-family: \"Victor Mono\";\n  src: url('/static/fonts/VictorMono.ttf') format(\"truetype\");\n}\n\n:root {\n  --ifm-font-family-monospace: \"Inter\";\n  --ifm-font-family-base: \"Inter\";\n}\n\ncode {\n  font-family: \"Victor Mono\", monospace;\n}\n\ncode[class*=\"language-\"],\npre[class*=\"language-\"] {\n  font-family: \"Victor Mono\", monospace;\n}\n\n/* Dev settings */\n\n[data-theme=\"dark\"]\n  .themedImage_node_modules-\\@docusaurus-theme-classic-lib-theme-ThemedImage-styles-module {\n  filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(226deg)\n    brightness(102%) contrast(101%);\n}\n\n[data-theme=\"light\"]\n  .themedImage_node_modules-\\@docusaurus-theme-classic-lib-theme-ThemedImage-styles-module {\n  filter: invert(0%) sepia(8%) saturate(2885%) hue-rotate(67deg) brightness(84%)\n    contrast(87%);\n}\n\na.getStarted_src-pages-styles-module {\n  color: white;\n}\n\ntable {\n  /* We need this to be able to use border-radius. */\n  border-collapse: separate;\n\n  /* Add a 1px border spacing for out box-shadow to fit into. Increase this if you want to increase the border width. */\n  border-spacing: 1px;\n}\n\ntable th,\ntable td {\n  /* Remove any borders from our stylesheet. */\n  border: 0;\n\n  /* Use the spread value on the box-shadow to set the border width. */\n  box-shadow: 0 0 0 1px #c8c9cc;\n}\n\ntable th:first-child {\n  border-top-left-radius: 6.4px;\n}\n\ntable th:last-child {\n  border-top-right-radius: 6.4px;\n}\n\ntable tr:last-child td:first-child {\n  border-bottom-left-radius: 6.4px;\n}\n\ntable tr:last-child td:last-child {\n  border-bottom-right-radius: 6.4px;\n}\n"
  },
  {
    "path": "website/src/css/prism-rose-pine-moon.css",
    "content": "/**\n * MIT License\n * Rosé Pine Theme\n * https://github.com/rose-pine\n * Ported for PrismJS by fvrests [@fvrests]\n */\n\n code[class*=\"language-\"],\n pre[class*=\"language-\"] {\n   color: #e0def4;\n   background: #232136;\n   font-family: \"Cartograph CF\", ui-monospace, SFMono-Regular, Menlo, Monaco,\n     Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n   text-align: left;\n   white-space: pre;\n   word-spacing: normal;\n   word-break: normal;\n   word-wrap: normal;\n   line-height: 1.5;\n\n   -moz-tab-size: 4;\n   -o-tab-size: 4;\n   tab-size: 4;\n\n   -webkit-hyphens: none;\n   -moz-hyphens: none;\n   -ms-hyphens: none;\n   hyphens: none;\n\n   @media print {\n     text-shadow: none;\n   }\n }\n\n /* Selection */\n code[class*=\"language-\"]::-moz-selection,\n pre[class*=\"language-\"]::-moz-selection,\n code[class*=\"language-\"] ::-moz-selection,\n pre[class*=\"language-\"] ::-moz-selection {\n   background: #44415a;\n }\n\n code[class*=\"language-\"]::selection,\n pre[class*=\"language-\"]::selection,\n code[class*=\"language-\"] ::selection,\n pre[class*=\"language-\"] ::selection {\n   background: #44415a;\n }\n\n /* Code (block & inline) */\n :not(pre) > code[class*=\"language-\"],\n pre[class*=\"language-\"] {\n   color: #e0def4;\n   background: #232136;\n }\n\n /* Code blocks */\n pre[class*=\"language-\"] {\n   padding: 1em;\n   margin: 0.5em 0;\n   overflow: auto;\n }\n\n /* Inline code */\n :not(pre) > code[class*=\"language-\"] {\n   padding: 0.1em;\n   border-radius: 0.3em;\n   white-space: normal;\n   color: #e0def4;\n   background: #232136;\n }\n\n /* Text style & opacity */\n .token.entity {\n   cursor: help;\n }\n\n .token.important,\n .token.bold {\n   font-weight: bold;\n }\n\n .token.italic,\n .token.selector,\n .token.doctype,\n .token.attr-name,\n .token.inserted,\n .token.deleted,\n .token.comment,\n .token.prolog,\n .token.cdata,\n .token.constant,\n .token.parameter,\n .token.url {\n   font-style: italic;\n }\n\n .token.url {\n   text-decoration: underline;\n }\n\n .namespace {\n   opacity: 0.7;\n }\n\n /* Syntax highlighting */\n .token.constant {\n   color: #e0def4;\n }\n\n .token.comment,\n .token.prolog,\n .token.cdata,\n .token.punctuation {\n   color: #908caa;\n }\n\n .token.delimiter,\n .token.important,\n .token.atrule,\n .token.operator,\n .token.keyword {\n   color: #3e8fb0;\n }\n\n .token.tag,\n .token.tag .punctuation,\n .token.doctype,\n .token.variable,\n .token.regex,\n .token.class-name,\n .token.selector,\n .token.inserted {\n   color: #9ccfd8;\n }\n\n .token.boolean,\n .token.entity,\n .token.number,\n .token.symbol,\n .token.function {\n   color: #ea9a97;\n }\n\n .token.string,\n .token.char,\n .token.property,\n .token.attr-value,\n .token.attr-value .punctuation {\n   color: #f6c177;\n }\n\n .token.parameter,\n .token.url,\n .token.name,\n .token.attr-name,\n .token.builtin {\n   color: #c4a7e7;\n }\n\n .token.deleted {\n   color: #eb6f92;\n }\n\n /* Insertions & deletions */\n .token.inserted {\n   background: rgba(156 207 216 0.12);\n }\n\n .token.deleted {\n   background: rgba(235 111 146 0.12);\n }\n\n /* Line highlighting */\n pre[data-line] {\n   position: relative;\n }\n\n pre[class*=\"language-\"] > code[class*=\"language-\"] {\n   position: relative;\n   z-index: 1;\n }\n\n .line-highlight,\n .highlight-lines .highlighted {\n   position: absolute;\n   left: 0;\n   right: 0;\n   padding: inherit 0;\n   margin-top: 1em;\n\n   background: #44415a;\n   box-shadow: inset 5px 0 0 #e0def4;\n\n   z-index: 0;\n\n   pointer-events: none;\n\n   line-height: inherit;\n   white-space: pre;\n }\n"
  },
  {
    "path": "website/src/pages/index.js",
    "content": "import Link from \"@docusaurus/Link\";\nimport useBaseUrl from \"@docusaurus/useBaseUrl\";\nimport useDocusaurusContext from \"@docusaurus/useDocusaurusContext\";\nimport Layout from \"@theme/Layout\";\nimport classnames from \"classnames\";\nimport styles from \"./styles.module.css\";\n\nconst features = [\n  {\n    title: <>🎨 Beautiful & Intelligent</>,\n    description: (\n      <>\n        Transform your terminal with stunning themes and intelligent segments that display\n        Git status, cloud info, language versions, system metrics, and 180+ other contextual details.\n        Your prompt adapts to what you're working on.\n      </>\n    ),\n  },\n  {\n    title: <>⚡ Lightning Fast</>,\n    description: (\n      <>\n        Built with Go for blazing performance. Smart caching and async operations ensure\n        your prompt renders instantly, even with complex configurations and multiple segments.\n        No more waiting for your terminal.\n      </>\n    ),\n  },\n  {\n    title: <>🌍 Universal Compatibility</>,\n    description: (\n      <>\n        One configuration works everywhere - PowerShell, Bash, Zsh, Fish, Nu Shell, and more.\n        Windows, macOS, Linux, WSL, containers, SSH sessions. Write once, use everywhere\n        with zero vendor lock-in.\n      </>\n    ),\n  },\n];\n\nfunction Feature({ imageUrl, title, description }) {\n  const imgUrl = useBaseUrl(imageUrl);\n  return (\n    <div className={classnames(\"col col--4\", styles.feature)}>\n      {imgUrl && (\n        <div className=\"text--center\">\n          <img className={styles.featureImage} src={imgUrl} alt={title} />\n        </div>\n      )}\n      <h3>{title}</h3>\n      <p>{description}</p>\n    </div>\n  );\n}\n\nfunction Home() {\n  const context = useDocusaurusContext();\n  const { siteConfig = {} } = context;\n  return (\n    <Layout title=\"Home\" description={`${siteConfig.tagline}`}>\n      <header className={classnames(\"hero hero--primary\", styles.heroBanner)}>\n        <div className=\"container\">\n          <h1 className=\"hero__title\">{siteConfig.title}</h1>\n          <p className=\"hero__subtitle\">{siteConfig.tagline}</p>\n          <div className={styles.buttons}>\n            <Link\n              className={classnames(\n                \"button button--primary button--lg\",\n                styles.getStarted\n              )}\n              to={useBaseUrl(\"docs/\")}\n            >\n              Get Started &rarr;\n            </Link>\n            <Link\n              className={classnames(\n                \"button button--outline button--lg\",\n                styles.getStarted\n              )}\n              to={useBaseUrl(\"docs/themes\")}\n            >\n              See themes &rarr;\n            </Link>\n          </div>\n          <img className=\"hero--image\" src=\"/img/hero.png\" alt=\"Oh My Posh prompt\"></img>\n        </div>\n      </header>\n      <main>\n        {features && features.length > 0 && (\n          <section className={styles.features}>\n            <div className=\"container\">\n              <div className=\"row\">\n                {features.map((props, idx) => (\n                  <Feature key={idx} {...props} />\n                ))}\n              </div>\n            </div>\n          </section>\n        )}\n      </main>\n    </Layout>\n  );\n}\n\nexport default Home;\n"
  },
  {
    "path": "website/src/pages/privacy.mdx",
    "content": "---\ntitle: Privacy\ndescription: the privacy page\nhide_table_of_contents: true\n---\n\n# Privacy\n\n## What information does Oh My Posh collect?\n\nOh My Posh and its developer take your privacy very seriously.\nBeyond the information installer methods provides to developers that covered\nprovided by the package manager privacy policies,\nwe use _no third-party analytics or advertising frameworks inside the executable_.\nOh My Posh logs no information on you and has no interest in doing so.\n\n## What information does the Oh My Posh website collect?\n\nThe Oh My Posh website uses Application Insights [custom events][ai] to log anonymous usage data.\nWe do not collect any personally identifiable information.\n\nOh My Posh does not collect, transmit, distribute or sell your data.\n\n[ai]: https://learn.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics#trackevent\n"
  },
  {
    "path": "website/src/pages/styles.module.css",
    "content": "/* stylelint-disable docusaurus/copyright-header */\n\n/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  padding: 4rem 0;\n  min-height: 60vh;\n  text-align: center;\n  position: relative;\n  overflow: hidden;\n}\n\n@media screen and (max-width: 966px) {\n  .heroBanner {\n    padding: 2rem 0;\n  }\n}\n\n.buttons {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 1rem 1.5rem;\n  align-items: center;\n  justify-content: center;\n}\n\n.features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureImage {\n  height: 200px;\n  width: 200px;\n}\n\n.getStarted {\n  border-style: solid;\n  border-width: 1px;\n}\n"
  },
  {
    "path": "website/static/.nojekyll",
    "content": ""
  },
  {
    "path": "website/static/codepoints.csv",
    "content": "f500,f0001,vector_square\nf501,f0003,access_point\nf502,f0002,access_point_network\nf503,f0004,account\nf504,f0005,account_alert\nf505,f0006,account_box\nf506,f0007,account_box_outline\nf507,f0008,account_check\nf508,f0009,account_circle\nf509,f000a,account_convert\nf50a,f000b,account_key\nf50c,f000d,account_minus\nf50d,f000e,account_multiple\nf50e,f000f,account_multiple_outline\nf50f,f0010,account_multiple_plus\nf510,f0011,account_network\nf511,f0012,account_off\nf512,f0013,account_outline\nf513,f0014,account_plus\nf514,f0015,account_remove\nf515,f0016,account_search\nf516,f0017,account_star\nf517,f0018,orbit\nf518,f0019,account_switch\nf519,f001a,adjust\nf51a,f001b,air_conditioner\nf51b,f001c,airballoon\nf51c,f001d,airplane\nf51d,f001e,airplane_off\nf51f,f0020,alarm\nf520,f0021,alarm_check\nf521,f0022,alarm_multiple\nf522,f0023,alarm_off\nf523,f0024,alarm_plus\nf524,f0025,album\nf525,f0026,alert\nf526,f0027,alert_box\nf527,f0028,alert_circle\nf528,f0029,alert_octagon\nf529,f002a,alert_outline\nf52a,f002b,alpha\nf52b,f002c,alphabetical\nf52e,f002f,ambulance\nf52f,f0030,amplifier\nf530,f0031,anchor\nf531,f0032,android\nf533,f0034,android_studio\nf534,f0035,apple\nf535,f0036,apple_finder\nf536,f0037,apple_ios\nf538,f0039,apple_safari\nf539,f003a,font_awesome\nf53a,f003b,apps\nf53b,f003c,archive\nf53c,f003d,arrange_bring_forward\nf53d,f003e,arrange_bring_to_front\nf53e,f003f,arrange_send_backward\nf53f,f0040,arrange_send_to_back\nf540,f0041,arrow_all\nf541,f0042,arrow_bottom_left\nf542,f0043,arrow_bottom_right\nf543,f0044,arrow_collapse_all\nf544,f0045,arrow_down\nf545,f0046,arrow_down_thick\nf546,f0047,arrow_down_bold_circle\nf547,f0048,arrow_down_bold_circle_outline\nf548,f0049,arrow_down_bold_hexagon_outline\nf549,f004a,arrow_down_drop_circle\nf54a,f004b,arrow_down_drop_circle_outline\nf54b,f004c,arrow_expand_all\nf54c,f004d,arrow_left\nf54d,f004e,arrow_left_thick\nf54e,f004f,arrow_left_bold_circle\nf54f,f0050,arrow_left_bold_circle_outline\nf550,f0051,arrow_left_bold_hexagon_outline\nf551,f0052,arrow_left_drop_circle\nf552,f0053,arrow_left_drop_circle_outline\nf553,f0054,arrow_right\nf554,f0055,arrow_right_thick\nf555,f0056,arrow_right_bold_circle\nf556,f0057,arrow_right_bold_circle_outline\nf557,f0058,arrow_right_bold_hexagon_outline\nf558,f0059,arrow_right_drop_circle\nf559,f005a,arrow_right_drop_circle_outline\nf55a,f005b,arrow_top_left\nf55b,f005c,arrow_top_right\nf55c,f005d,arrow_up\nf55d,f005e,arrow_up_thick\nf55e,f005f,arrow_up_bold_circle\nf55f,f0060,arrow_up_bold_circle_outline\nf560,f0061,arrow_up_bold_hexagon_outline\nf561,f0062,arrow_up_drop_circle\nf562,f0063,arrow_up_drop_circle_outline\nf563,f0064,assistant\nf564,f0065,at\nf565,f0066,attachment\nf567,f0068,auto_fix\nf568,f0069,auto_upload\nf569,f006a,autorenew\nf56a,f006b,av_timer\nf56b,f006c,baby\nf56c,f006d,backburger\nf56d,f006e,backspace\nf56e,f006f,backup_restore\nf56f,f0070,bank\nf570,f0071,barcode\nf571,f0072,barcode_scan\nf572,f0073,barley\nf573,f0074,barrel\nf575,f0076,basket\nf576,f0077,basket_fill\nf577,f0078,basket_unfill\nf578,f0079,battery\nf579,f007a,battery_10\nf57a,f007b,battery_20\nf57b,f007c,battery_30\nf57c,f007d,battery_40\nf57d,f007e,battery_50\nf57e,f007f,battery_60\nf57f,f0080,battery_70\nf580,f0081,battery_80\nf581,f0082,battery_90\nf582,f0083,battery_alert\nf583,f0084,battery_charging\nf584,f0085,battery_charging_100\nf585,f0086,battery_charging_20\nf586,f0087,battery_charging_30\nf587,f0088,battery_charging_40\nf588,f0089,battery_charging_60\nf589,f008a,battery_charging_80\nf58a,f008b,battery_charging_90\nf58b,f17e4,battery_minus\nf58c,f008d,battery_negative\nf58d,f008e,battery_outline\nf58e,f17e6,battery_plus\nf58f,f0090,battery_positive\nf590,f0091,battery_unknown\nf591,f0092,beach\nf592,f0093,flask\nf593,f0094,flask_empty\nf594,f0095,flask_empty_outline\nf595,f0096,flask_outline\nf597,f0098,beer\nf599,f009a,bell\nf59a,f009b,bell_off\nf59b,f009c,bell_outline\nf59c,f009d,bell_plus\nf59d,f009e,bell_ring\nf59e,f009f,bell_ring_outline\nf59f,f00a0,bell_sleep\nf5a0,f00a1,beta\nf5a2,f00a3,bike\nf5a4,f00a5,binoculars\nf5a5,f00a6,bio\nf5a6,f00a7,biohazard\nf5a7,f00a8,bitbucket\nf5a8,f00a9,black_mesa\nf5aa,f0ceb,blender\nf5ab,f00ac,blinds\nf5ac,f00ad,block_helper\nf5ae,f00af,bluetooth\nf5af,f00b0,bluetooth_audio\nf5b0,f00b1,bluetooth_connect\nf5b1,f00b2,bluetooth_off\nf5b2,f00b3,bluetooth_settings\nf5b3,f00b4,bluetooth_transfer\nf5b4,f00b5,blur\nf5b5,f00b6,blur_linear\nf5b6,f00b7,blur_off\nf5b7,f00b8,blur_radial\nf5b8,f00b9,bone\nf5b9,f00ba,book\nf5ba,f00bb,book_multiple\nf5bc,f00bd,book_open\nf5bd,f14f7,book_open_variant\nf5be,f00bf,book_variant\nf5bf,f00c0,bookmark\nf5c0,f00c1,bookmark_check\nf5c1,f00c2,bookmark_music\nf5c2,f00c3,bookmark_outline\nf5c3,f00c4,bookmark_plus_outline\nf5c4,f00c5,bookmark_plus\nf5c5,f00c6,bookmark_remove\nf5c6,f00c7,border_all\nf5c7,f00c8,border_bottom\nf5c8,f00c9,border_color\nf5c9,f00ca,border_horizontal\nf5ca,f00cb,border_inside\nf5cb,f00cc,border_left\nf5cc,f00cd,border_none\nf5cd,f00ce,border_outside\nf5ce,f00cf,border_right\nf5cf,f00d0,border_style\nf5d0,f00d1,border_top\nf5d1,f00d2,border_vertical\nf5d2,f00d3,bowling\nf5d3,f00d4,box\nf5d4,f00d5,box_cutter\nf5d5,f00d6,briefcase\nf5d6,f00d7,briefcase_check\nf5d7,f00d8,briefcase_download\nf5d8,f00d9,briefcase_upload\nf5d9,f00da,brightness_1\nf5da,f00db,brightness_2\nf5db,f00dc,brightness_3\nf5dc,f00dd,brightness_4\nf5dd,f00de,brightness_5\nf5de,f00df,brightness_6\nf5df,f00e0,brightness_7\nf5e0,f00e1,brightness_auto\nf5e1,f00e2,broom\nf5e2,f00e3,brush\nf5e3,f00e4,bug\nf5e4,f00e5,bulletin_board\nf5e5,f00e6,bullhorn\nf5e6,f00e7,bus\nf5e7,f00e8,cached\nf5e8,f00e9,cake\nf5e9,f00ea,cake_layered\nf5ea,f00eb,cake_variant\nf5eb,f00ec,calculator\nf5ec,f00ed,calendar\nf5ed,f00ee,calendar_blank\nf5ee,f00ef,calendar_check\nf5ef,f00f0,calendar_clock\nf5f0,f00f1,calendar_multiple\nf5f1,f00f2,calendar_multiple_check\nf5f2,f00f3,calendar_plus\nf5f3,f00f4,calendar_remove\nf5f4,f00f5,calendar_text\nf5f5,f00f6,calendar_today\nf5f6,f00f7,call_made\nf5f7,f00f8,call_merge\nf5f8,f00f9,call_missed\nf5f9,f00fa,call_received\nf5fa,f00fb,call_split\nf5fb,f00fc,camcorder\nf5fe,f00ff,camcorder_off\nf5ff,f0100,camera\nf600,f0101,camera_enhance\nf601,f0102,camera_front\nf602,f0103,camera_front_variant\nf603,f0104,camera_iris\nf604,f0105,camera_party_mode\nf605,f0106,camera_rear\nf606,f0107,camera_rear_variant\nf607,f0108,camera_switch\nf608,f0109,camera_timer\nf609,f010a,candycane\nf60a,f010b,car\nf60b,f010c,car_battery\nf60c,f010d,car_connected\nf60d,f010e,car_wash\nf60e,f010f,carrot\nf60f,f0110,cart\nf610,f0111,cart_outline\nf611,f0112,cart_plus\nf612,f0113,case_sensitive_alt\nf613,f0114,cash\nf614,f0115,cash_100\nf615,f0116,cash_multiple\nf617,f0118,cast\nf618,f0119,cast_connected\nf619,f011a,castle\nf61a,f011b,cat\nf61b,f011c,cellphone\nf61d,f011e,cellphone_basic\nf61e,f011f,cellphone_dock\nf620,f0121,cellphone_link\nf621,f0122,cellphone_link_off\nf622,f0123,cellphone_settings\nf623,f0124,certificate\nf624,f0125,chair_school\nf625,f0126,chart_arc\nf626,f0127,chart_areaspline\nf627,f0128,chart_bar\nf628,f0129,chart_histogram\nf629,f012a,chart_line\nf62a,f012b,chart_pie\nf62b,f012c,check\nf62c,f012d,check_all\nf62d,f012e,checkbox_blank\nf62e,f0765,checkbox_blank_circle\nf62f,f0766,checkbox_blank_circle_outline\nf630,f0131,checkbox_blank_outline\nf631,f0132,checkbox_marked\nf632,f0133,checkbox_marked_circle\nf633,f0134,checkbox_marked_circle_outline\nf634,f0135,checkbox_marked_outline\nf635,f0136,checkbox_multiple_blank\nf636,f0137,checkbox_multiple_blank_outline\nf637,f0138,checkbox_multiple_marked\nf638,f0139,checkbox_multiple_marked_outline\nf639,f013a,checkerboard\nf63a,f013b,chemical_weapon\nf63b,f013c,chevron_double_down\nf63c,f013d,chevron_double_left\nf63d,f013e,chevron_double_right\nf63e,f013f,chevron_double_up\nf63f,f0140,chevron_down\nf640,f0141,chevron_left\nf641,f0142,chevron_right\nf642,f0143,chevron_up\nf643,f0144,church\nf645,f0146,city\nf646,f0147,clipboard\nf647,f0148,clipboard_account\nf648,f0149,clipboard_alert\nf649,f014a,clipboard_arrow_down\nf64a,f014b,clipboard_arrow_left\nf64b,f014e,clipboard_check\nf64c,f014c,clipboard_outline\nf64d,f014d,clipboard_text\nf64e,f014f,clippy\nf64f,f0954,clock\nf650,f0151,clock_end\nf651,f0152,clock_fast\nf652,f0153,clock_in\nf653,f0154,clock_out\nf654,f0155,clock_start\nf655,f0156,close\nf656,f0157,close_box\nf657,f0158,close_box_outline\nf658,f0159,close_circle\nf659,f015a,close_circle_outline\nf65a,f015b,close_network\nf65b,f015c,close_octagon\nf65c,f015d,close_octagon_outline\nf65d,f015e,closed_caption\nf65e,f015f,cloud\nf65f,f0160,cloud_check\nf660,f0161,cloud_circle\nf661,f0162,cloud_download\nf662,f0163,cloud_outline\nf663,f0164,cloud_off_outline\nf664,f0165,cloud_print\nf665,f0166,cloud_print_outline\nf666,f0167,cloud_upload\nf667,f0168,code_array\nf668,f0169,code_braces\nf669,f016a,code_brackets\nf66a,f016b,code_equal\nf66b,f016c,code_greater_than\nf66c,f016d,code_greater_than_or_equal\nf66d,f016e,code_less_than\nf66e,f016f,code_less_than_or_equal\nf66f,f0170,code_not_equal\nf670,f0171,code_not_equal_variant\nf671,f0172,code_parentheses\nf672,f0173,code_string\nf673,f0174,code_tags\nf674,f0175,codepen\nf675,f0176,coffee\nf676,f0177,coffee_to_go\nf678,f0179,color_helper\nf679,f017a,comment\nf67a,f017b,comment_account\nf67b,f017c,comment_account_outline\nf67c,f017d,comment_alert\nf67d,f017e,comment_alert_outline\nf67e,f017f,comment_check\nf67f,f0180,comment_check_outline\nf680,f0181,comment_multiple_outline\nf681,f0182,comment_outline\nf682,f0183,comment_plus_outline\nf683,f0184,comment_processing\nf684,f0185,comment_processing_outline\nf685,f0186,comment_question_outline\nf686,f0187,comment_remove_outline\nf687,f0188,comment_text\nf688,f0189,comment_text_outline\nf689,f018a,compare\nf68a,f018b,compass\nf68b,f018c,compass_outline\nf68c,f018d,console\nf68e,f018f,content_copy\nf68f,f0190,content_cut\nf690,f0191,content_duplicate\nf691,f0192,content_paste\nf692,f0193,content_save\nf693,f0194,content_save_all\nf694,f0195,contrast\nf695,f0196,contrast_box\nf696,f0197,contrast_circle\nf697,f0198,cookie\nf698,f0199,counter\nf699,f019a,cow\nf69a,f0fef,credit_card\nf69b,f0ff0,credit_card_multiple\nf69c,f0ff4,credit_card_scan\nf69d,f019e,crop\nf69e,f019f,crop_free\nf69f,f01a0,crop_landscape\nf6a0,f01a1,crop_portrait\nf6a1,f01a2,crop_square\nf6a2,f01a3,crosshairs\nf6a3,f01a4,crosshairs_gps\nf6a4,f01a5,crown\nf6a5,f01a6,cube\nf6a6,f01a7,cube_outline\nf6a7,f01a8,cube_send\nf6a8,f01a9,cube_unfolded\nf6a9,f01aa,cup\nf6aa,f01ab,cup_water\nf6ab,f01ac,currency_btc\nf6ac,f01ad,currency_eur\nf6ad,f01ae,currency_gbp\nf6ae,f01af,currency_inr\nf6af,f01b0,currency_ngn\nf6b0,f01b1,currency_rub\nf6b1,f01b2,currency_try\nf6b2,f01c1,currency_usd\nf6b3,f01c0,cursor_default\nf6b4,f01bf,cursor_default_outline\nf6b5,f01be,cursor_move\nf6b6,f01bd,cursor_pointer\nf6b7,f01bc,database\nf6b8,f01bb,database_minus\nf6b9,f01ba,database_plus\nf6ba,f01b9,debug_step_into\nf6bb,f01b8,debug_step_out\nf6bc,f01b7,debug_step_over\nf6bd,f01b6,decimal_decrease\nf6be,f01b5,decimal_increase\nf6bf,f01b4,delete\nf6c0,f01b3,delete_variant\nf6c1,f01c2,delta\nf6c2,f01c3,deskphone\nf6c3,f01c4,desktop_mac\nf6c4,f01c5,desktop_tower\nf6c5,f01c6,details\nf6c6,f01c7,deviantart\nf6c7,f0b8a,diamond\nf6c8,f0674,creation\nf6c9,f01ca,dice_1\nf6ca,f01cb,dice_2\nf6cb,f01cc,dice_3\nf6cc,f01cd,dice_4\nf6cd,f01ce,dice_5\nf6ce,f01cf,dice_6\nf6cf,f01d0,directions\nf6d1,f01d2,disqus\nf6d3,f01d4,division\nf6d4,f01d5,division_box\nf6d5,f01d6,dns\nf6d6,f01d7,domain\nf6d7,f01d8,dots_horizontal\nf6d8,f01d9,dots_vertical\nf6d9,f01da,download\nf6da,f01db,drag\nf6db,f01dc,drag_horizontal\nf6dc,f01dd,drag_vertical\nf6dd,f01de,drawing\nf6de,f01df,drawing_box\nf6e1,f01e2,drone\nf6e2,f01e3,dropbox\nf6e3,f01e4,drupal\nf6e4,f01e5,duck\nf6e5,f01e6,dumbbell\nf6e6,f01e7,earth\nf6e7,f01e8,earth_off\nf6e9,f01ea,eject\nf6ea,f01eb,elevation_decline\nf6eb,f01ec,elevation_rise\nf6ec,f01ed,elevator\nf6ed,f01ee,email\nf6ee,f01ef,email_open\nf6ef,f01f0,email_outline\nf6f1,f0c68,emoticon\nf6f2,f0c6b,emoticon_cool\nf6f3,f0c6f,emoticon_devil\nf6f4,f0c71,emoticon_happy\nf6f5,f0c74,emoticon_neutral\nf6f6,f01f7,emoticon_poop\nf6f7,f0c76,emoticon_sad\nf6f8,f01f9,emoticon_tongue\nf6f9,f01fa,engine\nf6fa,f01fb,engine_outline\nf6fb,f01fc,equal\nf6fc,f01fd,equal_box\nf6fd,f01fe,eraser\nf6fe,f01ff,escalator\nf6ff,f0200,ethernet\nf700,f0201,ethernet_cable\nf701,f0202,ethernet_cable_off\nf703,f0204,evernote\nf704,f0205,exclamation\nf705,f05fc,exit_to_app\nf706,f0207,export\nf707,f0208,eye\nf708,f0209,eye_off\nf709,f020a,eyedropper\nf70a,f020b,eyedropper_variant\nf70b,f020c,facebook\nf70d,f020e,facebook_messenger\nf70e,f020f,factory\nf70f,f0210,fan\nf710,f0211,fast_forward\nf711,f0212,fax\nf712,f0213,ferry\nf713,f0214,file\nf714,f0215,file_chart\nf715,f0216,file_check\nf716,f0217,file_cloud\nf717,f0218,file_delimited\nf718,f0219,file_document\nf71a,f021b,file_excel\nf71b,f021c,file_excel_box\nf71c,f021d,file_export\nf71d,f021e,file_find\nf71e,f021f,file_image\nf71f,f0220,file_import\nf720,f0221,file_lock\nf721,f0222,file_multiple\nf722,f0223,file_music\nf723,f0224,file_outline\nf725,f0226,file_pdf_box\nf726,f0227,file_powerpoint\nf727,f0228,file_powerpoint_box\nf728,f0229,file_presentation_box\nf729,f022a,file_send\nf72a,f022b,file_video\nf72b,f022c,file_word\nf72c,f022d,file_word_box\nf72e,f022f,film\nf72f,f0230,filmstrip\nf730,f0231,filmstrip_off\nf731,f0232,filter\nf732,f0233,filter_outline\nf733,f0234,filter_remove\nf734,f0235,filter_remove_outline\nf735,f0236,filter_variant\nf736,f0237,fingerprint\nf737,f0238,fire\nf738,f0239,firefox\nf739,f023a,fish\nf73a,f023b,flag\nf73b,f023c,flag_checkered\nf73c,f023d,flag_outline\nf73d,f023e,flag_variant_outline\nf73e,f023f,flag_triangle\nf73f,f0240,flag_variant\nf740,f0241,flash\nf741,f0242,flash_auto\nf742,f0243,flash_off\nf743,f0244,flashlight\nf744,f0245,flashlight_off\nf746,f0247,flip_to_back\nf747,f0248,flip_to_front\nf748,f0249,floppy\nf749,f024a,flower\nf74a,f024b,folder\nf74b,f024c,folder_account\nf74c,f024d,folder_download\nf74d,f024e,folder_google_drive\nf74e,f024f,folder_image\nf74f,f0250,folder_lock\nf750,f0251,folder_lock_open\nf751,f0252,folder_move\nf752,f0253,folder_multiple\nf753,f0254,folder_multiple_image\nf754,f0255,folder_multiple_outline\nf755,f0256,folder_outline\nf756,f0257,folder_plus\nf757,f0258,folder_remove\nf758,f0259,folder_upload\nf759,f025a,food\nf75a,f025b,food_apple\nf75b,f025c,food_variant\nf75c,f025d,football\nf75d,f025e,football_australian\nf75e,f025f,football_helmet\nf75f,f0260,format_align_center\nf760,f0261,format_align_justify\nf761,f0262,format_align_left\nf762,f0263,format_align_right\nf763,f0264,format_bold\nf764,f0265,format_clear\nf765,f0266,format_color_fill\nf766,f0267,format_float_center\nf767,f0268,format_float_left\nf768,f0269,format_float_none\nf769,f026a,format_float_right\nf76a,f026b,format_header_1\nf76b,f026c,format_header_2\nf76c,f026d,format_header_3\nf76d,f026e,format_header_4\nf76e,f026f,format_header_5\nf76f,f0270,format_header_6\nf770,f0271,format_header_decrease\nf771,f0272,format_header_equal\nf772,f0273,format_header_increase\nf773,f0274,format_header_pound\nf774,f0275,format_indent_decrease\nf775,f0276,format_indent_increase\nf776,f0277,format_italic\nf777,f0278,format_line_spacing\nf778,f0279,format_list_bulleted\nf779,f027a,format_list_bulleted_type\nf77b,f027c,format_paint\nf77c,f027d,format_paragraph\nf77d,f027e,format_quote_close\nf77e,f027f,format_size\nf77f,f0280,format_strikethrough\nf780,f0281,format_strikethrough_variant\nf781,f0282,format_subscript\nf782,f0283,format_superscript\nf783,f0284,format_text\nf784,f0285,format_textdirection_l_to_r\nf785,f0286,format_textdirection_r_to_l\nf786,f0287,format_underline\nf787,f0288,format_wrap_inline\nf788,f0289,format_wrap_square\nf789,f028a,format_wrap_tight\nf78a,f028b,format_wrap_top_bottom\nf78b,f028c,forum\nf78c,f028d,forward\nf78e,f0290,fridge\nf792,f0293,fullscreen\nf793,f0294,fullscreen_exit\nf794,f0295,function\nf795,f0296,gamepad\nf796,f0297,gamepad_variant\nf797,f0298,gas_station\nf798,f0299,gate\nf799,f029a,gauge\nf79a,f029b,gavel\nf79b,f029c,gender_female\nf79c,f029d,gender_male\nf79d,f029e,gender_male_female\nf79e,f029f,gender_transgender\nf79f,f02a0,ghost\nf7a0,f0e44,gift\nf7a1,f02a2,git\nf7a4,f02a5,glass_flute\nf7a5,f02a6,glass_mug\nf7a6,f02a7,glass_stange\nf7a7,f02a8,glass_tulip\nf7a9,f02aa,glasses\nf7aa,f02ab,gmail\nf7ab,f02ac,gnome\nf7ac,f02ad,google\nf7ad,f02ae,google_cardboard\nf7ae,f02af,google_chrome\nf7af,f02b0,google_circles\nf7b0,f02b1,google_circles_communities\nf7b1,f02b2,google_circles_extended\nf7b2,f02b3,google_circles_group\nf7b3,f02b4,google_controller\nf7b4,f02b5,google_controller_off\nf7b5,f02b6,google_drive\nf7b6,f02b7,google_earth\nf7b7,f02b8,google_glass\nf7b8,f02b9,google_nearby\nf7bb,f02bc,google_play\nf7bc,f02bd,google_plus\nf7be,f02bf,google_translate\nf7c0,f02c1,grid\nf7c1,f02c2,grid_off\nf7c2,f02c3,group\nf7c3,f02c4,guitar_electric\nf7c4,f02c5,guitar_pick\nf7c5,f02c6,guitar_pick_outline\nf7c6,f02c7,hand_pointing_right\nf7c7,f02c8,hanger\nf7c9,f02ca,harddisk\nf7ca,f02cb,headphones\nf7cb,f02cc,headphones_box\nf7cc,f02cd,headphones_settings\nf7cd,f02ce,headset\nf7ce,f02cf,headset_dock\nf7cf,f02d0,headset_off\nf7d0,f08d0,heart\nf7d1,f02d2,heart_box\nf7d2,f02d3,heart_box_outline\nf7d3,f02d4,heart_broken\nf7d4,f18a0,heart_outline\nf7d5,f02d6,help\nf7d6,f02d7,help_circle\nf7d7,f02d8,hexagon\nf7d8,f02d9,hexagon_outline\nf7d9,f02da,history\nf7da,f02db,hololens\nf7db,f02dc,home\nf7dc,f02dd,home_modern\nf7dd,f02de,home_variant\nf7de,f02df,hops\nf7df,f0ff6,hospital\nf7e0,f02e1,hospital_building\nf7e1,f02e2,hospital_marker\nf7e5,f02e6,human\nf7e6,f02e7,human_child\nf7e7,f02e8,human_male_female\nf7e8,f02e9,image\nf7e9,f02ea,image_album\nf7ea,f02eb,image_area\nf7eb,f02ec,image_area_close\nf7ec,f02ed,image_broken\nf7ed,f02ee,image_broken_variant\nf7ef,f02f0,image_filter_black_white\nf7f0,f02f1,image_filter_center_focus\nf7f1,f02f2,image_filter_center_focus_weak\nf7f2,f02f3,image_filter_drama\nf7f3,f02f4,image_filter_frames\nf7f4,f0509,image_filter_hdr\nf7f5,f02f6,image_filter_none\nf7f6,f02f7,image_filter_tilt_shift\nf7f7,f02f8,image_filter_vintage\nf7f8,f02f9,image_multiple\nf7f9,f02fa,import\nf7fa,f02fb,inbox_arrow_down\nf7fb,f02fc,information\nf7fc,f02fd,information_outline\nf7fd,f02fe,instagram\nf800,f0301,invert_colors\nf801,f0302,jeepney\nf802,f0303,jira\nf803,f0304,jsfiddle\nf804,f0305,keg\nf805,f0306,key\nf806,f0307,key_change\nf807,f0308,key_minus\nf808,f0309,key_plus\nf809,f030a,key_remove\nf80a,f030b,key_variant\nf80b,f030c,keyboard\nf80c,f030d,keyboard_backspace\nf80d,f030e,keyboard_caps\nf80e,f030f,keyboard_close\nf80f,f0310,keyboard_off\nf810,f0311,keyboard_return\nf811,f0312,keyboard_tab\nf812,f0313,keyboard_variant\nf813,f0314,kodi\nf814,f0315,label\nf815,f0316,label_outline\nf816,f0317,lan\nf817,f0318,lan_connect\nf818,f0319,lan_disconnect\nf819,f031a,lan_pending\nf81a,f031b,language_csharp\nf81b,f031c,language_css3\nf81c,f031d,language_html5\nf81d,f031e,language_javascript\nf81e,f031f,language_php\nf81f,f0320,language_python\nf821,f0322,laptop\nf826,f0327,launch\nf827,f0328,layers\nf828,f0329,layers_off\nf829,f032a,leaf\nf82a,f032b,led_off\nf82b,f032c,led_on\nf82c,f032d,led_outline\nf82d,f032e,led_variant_off\nf82e,f032f,led_variant_on\nf82f,f0330,led_variant_outline\nf830,f0331,library\nf834,f0335,lightbulb\nf835,f0336,lightbulb_outline\nf836,f0337,link\nf837,f0338,link_off\nf838,f0339,link_variant\nf839,f033a,link_variant_off\nf83a,f033b,linkedin\nf83c,f033d,linux\nf83d,f033e,lock\nf83e,f033f,lock_open\nf83f,f0340,lock_open_outline\nf840,f0341,lock_outline\nf841,f0342,login\nf842,f0343,logout\nf843,f0344,looks\nf844,f0345,loupe\nf845,f0346,lumx\nf846,f0347,magnet\nf847,f0348,magnet_on\nf848,f0349,magnify\nf849,f034a,magnify_minus\nf84a,f034b,magnify_plus\nf84c,f034d,map\nf84d,f034e,map_marker\nf84e,f034f,map_marker_circle\nf84f,f0350,map_marker_multiple\nf850,f0351,map_marker_off\nf851,f0352,map_marker_radius\nf852,f0353,margin\nf854,f0355,marker_check\nf856,f0357,material_ui\nf857,f0358,math_compass\nf85a,f035b,memory\nf85b,f035c,menu\nf85c,f035d,menu_down\nf85d,f035e,menu_left\nf85e,f035f,menu_right\nf85f,f0360,menu_up\nf860,f0361,message\nf861,f0362,message_alert\nf862,f0363,message_draw\nf863,f0364,message_image\nf864,f0365,message_outline\nf865,f0366,message_processing\nf866,f0367,message_reply\nf867,f0368,message_reply_text\nf868,f0369,message_text\nf869,f036a,message_text_outline\nf86a,f036b,message_video\nf86b,f036c,microphone\nf86c,f036d,microphone_off\nf86d,f036e,microphone_outline\nf86e,f036f,microphone_settings\nf86f,f0370,microphone_variant\nf870,f0371,microphone_variant_off\nf871,f0372,microsoft\nf872,f0373,minecraft\nf873,f0374,minus\nf874,f0375,minus_box\nf875,f0376,minus_circle\nf876,f0377,minus_circle_outline\nf877,f0378,minus_network\nf878,f0379,monitor\nf879,f037a,monitor_multiple\nf87a,f037b,more\nf87b,f037c,motorbike\nf87c,f037d,mouse\nf87d,f037e,mouse_off\nf87e,f037f,mouse_variant\nf87f,f0380,mouse_variant_off\nf880,f0381,movie\nf881,f0382,multiplication\nf882,f0383,multiplication_box\nf883,f0384,music_box\nf884,f0385,music_box_outline\nf885,f0386,music_circle\nf886,f0388,music_note\nf888,f0389,music_note_half\nf889,f038a,music_note_off\nf88a,f038b,music_note_quarter\nf88b,f038c,music_note_sixteenth\nf88c,f038d,music_note_whole\nf88d,f038e,nature\nf88e,f038f,nature_people\nf88f,f0390,navigation\nf890,f0391,needle\nf893,f0394,new_box\nf894,f0395,newspaper\nf895,f0396,nfc\nf896,f0397,nfc_tap\nf897,f0398,nfc_variant\nf898,f0399,nodejs\nf899,f039a,note\nf89a,f039b,note_outline\nf89b,f039c,note_plus\nf89c,f039d,note_plus_outline\nf89d,f039e,note_text\nf89e,f039f,notification_clear_all\nf89f,f03a0,numeric\nf8a0,f03a1,numeric_0_box\nf8a1,f03a2,numeric_0_box_multiple_outline\nf8a2,f03a3,numeric_0_box_outline\nf8a3,f03a4,numeric_1_box\nf8a4,f03a5,numeric_1_box_multiple_outline\nf8a5,f03a6,numeric_1_box_outline\nf8a6,f03a7,numeric_2_box\nf8a7,f03a8,numeric_2_box_multiple_outline\nf8a8,f03a9,numeric_2_box_outline\nf8a9,f03aa,numeric_3_box\nf8aa,f03ab,numeric_3_box_multiple_outline\nf8ab,f03ac,numeric_3_box_outline\nf8ac,f03ad,numeric_4_box\nf8ad,f03b2,numeric_4_box_multiple_outline\nf8ae,f03ae,numeric_4_box_outline\nf8af,f03b1,numeric_5_box\nf8b0,f03af,numeric_5_box_multiple_outline\nf8b1,f03b0,numeric_5_box_outline\nf8b2,f03b3,numeric_6_box\nf8b3,f03b4,numeric_6_box_multiple_outline\nf8b4,f03b5,numeric_6_box_outline\nf8b5,f03b6,numeric_7_box\nf8b6,f03b7,numeric_7_box_multiple_outline\nf8b7,f03b8,numeric_7_box_outline\nf8b8,f03b9,numeric_8_box\nf8b9,f03ba,numeric_8_box_multiple_outline\nf8ba,f03bb,numeric_8_box_outline\nf8bb,f03bc,numeric_9_box\nf8bc,f03bd,numeric_9_box_multiple_outline\nf8bd,f03be,numeric_9_box_outline\nf8be,f03bf,numeric_9_plus_box\nf8bf,f03c0,numeric_9_plus_box_multiple_outline\nf8c0,f03c1,numeric_9_plus_box_outline\nf8c1,f03c2,nutrition\nf8c2,f03c3,octagon\nf8c3,f03c4,octagon_outline\nf8c4,f03c5,odnoklassniki\nf8c6,f03c7,oil\nf8c7,f0ff8,oil_temperature\nf8c8,f03c9,omega\nf8ca,f03cb,open_in_app\nf8cb,f03cc,open_in_new\nf8cc,f03cd,openid\nf8cd,f03ce,opera\nf8ce,f03cf,ornament\nf8cf,f03d0,ornament_variant\nf8d0,f03d1,inbox_arrow_up\nf8d1,f03d2,owl\nf8d2,f03d3,package\nf8d3,f03d4,package_down\nf8d4,f03d5,package_up\nf8d5,f03d6,package_variant\nf8d6,f03d7,package_variant_closed\nf8d7,f03d8,palette\nf8d8,f03d9,palette_advanced\nf8d9,f03da,panda\nf8da,f03db,pandora\nf8db,f03dc,panorama\nf8dc,f03dd,panorama_fisheye\nf8dd,f1928,panorama_horizontal\nf8de,f1929,panorama_vertical\nf8df,f195f,panorama_wide_angle\nf8e0,f03e1,paper_cut_vertical\nf8e1,f03e2,paperclip\nf8e2,f03e3,parking\nf8e3,f03e4,pause\nf8e4,f03e5,pause_circle\nf8e5,f03e6,pause_circle_outline\nf8e6,f03e7,pause_octagon\nf8e7,f03e8,pause_octagon_outline\nf8e8,f03e9,paw\nf8e9,f03ea,pen\nf8ea,f03eb,pencil\nf8eb,f03ec,pencil_box\nf8ec,f03ed,pencil_box_outline\nf8ed,f03ee,pencil_lock\nf8ee,f03ef,pencil_off\nf8ef,f03f0,percent\nf8f1,f03f2,phone\nf8f2,f03f3,phone_bluetooth\nf8f3,f03f4,phone_forward\nf8f4,f03f5,phone_hangup\nf8f5,f03f6,phone_in_talk\nf8f6,f03f7,phone_incoming\nf8f8,f03f9,phone_log\nf8f9,f03fa,phone_missed\nf8fa,f03fb,phone_outgoing\nf8fb,f03fc,phone_paused\nf8fc,f03fd,phone_settings\nf8fd,f03fe,phone_voip\nf8fe,f03ff,pi\nf8ff,f0400,pi_box\nf900,f0401,pig\nf901,f0402,pill\nf902,f0403,pin\nf903,f0404,pin_off\nf904,f0405,pine_tree\nf905,f0406,pine_tree_box\nf906,f0407,pinterest\nf908,f0409,pizza\nf909,f040a,play\nf90a,f040b,play_box_outline\nf90b,f040c,play_circle\nf90c,f040d,play_circle_outline\nf90d,f040e,play_pause\nf90e,f040f,play_protected_content\nf90f,f0410,playlist_minus\nf910,f0411,playlist_play\nf911,f0412,playlist_plus\nf912,f0413,playlist_remove\nf914,f0415,plus\nf915,f0416,plus_box\nf916,f0417,plus_circle\nf917,f0418,plus_circle_multiple_outline\nf918,f0419,plus_circle_outline\nf919,f041a,plus_network\nf91c,f041d,pokeball\nf91d,f041e,polaroid\nf91e,f041f,poll\nf920,f0421,polymer\nf921,f0422,popcorn\nf922,f0423,pound\nf923,f0424,pound_box\nf924,f0425,power\nf925,f0426,power_settings\nf926,f0427,power_socket\nf927,f0428,presentation\nf928,f0429,presentation_play\nf929,f042a,printer\nf92a,f042b,printer_3d\nf92b,f042c,printer_alert\nf92c,f042d,professional_hexagon\nf92d,f042e,projector\nf92e,f042f,projector_screen\nf92f,f0430,pulse\nf930,f0431,puzzle\nf931,f0432,qrcode\nf932,f0433,qrcode_scan\nf933,f0434,quadcopter\nf934,f0435,quality_high\nf936,f0437,radar\nf937,f0438,radiator\nf938,f0439,radio\nf939,f043a,radio_handheld\nf93a,f043b,radio_tower\nf93b,f043c,radioactive\nf93d,f043e,radiobox_marked\nf93f,f0440,ray_end\nf940,f0441,ray_end_arrow\nf941,f0442,ray_start\nf942,f0443,ray_start_arrow\nf943,f0444,ray_start_end\nf944,f0445,ray_vertex\nf945,f0446,lastpass\nf946,f0447,read\nf947,f0448,youtube_tv\nf948,f0449,receipt\nf949,f044a,record\nf94a,f044b,record_rec\nf94b,f044c,recycle\nf94c,f044d,reddit\nf94d,f044e,redo\nf94e,f044f,redo_variant\nf94f,f0450,refresh\nf950,f0451,regex\nf951,f0452,relative_scale\nf952,f0453,reload\nf953,f0454,remote\nf954,f0455,rename_box\nf955,f0456,repeat\nf956,f0457,repeat_off\nf957,f0458,repeat_once\nf958,f0459,replay\nf959,f045a,reply\nf95a,f045b,reply_all\nf95b,f045c,reproduction\nf95c,f045d,resize_bottom_right\nf95d,f045e,responsive\nf95e,f045f,rewind\nf95f,f0460,ribbon\nf960,f0461,road\nf961,f0462,road_variant\nf962,f0463,rocket\nf963,f0ec7,rotate_3d\nf964,f0465,rotate_left\nf965,f0466,rotate_left_variant\nf966,f0467,rotate_right\nf967,f0468,rotate_right_variant\nf968,f0469,router_wireless\nf969,f046a,routes\nf96a,f046b,rss\nf96b,f046c,rss_box\nf96c,f046d,ruler\nf96d,f046e,run_fast\nf96e,f046f,sale\nf96f,f0470,satellite\nf970,f0471,satellite_variant\nf971,f0472,scale\nf972,f0473,scale_bathroom\nf973,f0474,school\nf974,f0475,screen_rotation\nf975,f0478,screen_rotation_lock\nf976,f0476,screwdriver\nf977,f0bc1,script\nf978,f0479,sd\nf979,f047a,seal\nf97a,f047b,seat_flat\nf97b,f047c,seat_flat_angled\nf97c,f047d,seat_individual_suite\nf97d,f047e,seat_legroom_extra\nf97e,f047f,seat_legroom_normal\nf97f,f0480,seat_legroom_reduced\nf980,f0481,seat_recline_extra\nf981,f0482,seat_recline_normal\nf982,f0483,security\nf983,f0484,security_network\nf984,f0485,select\nf985,f0486,select_all\nf986,f0487,select_inverse\nf987,f0488,select_off\nf988,f0489,selection\nf989,f048a,send\nf98a,f048b,server\nf98b,f048c,server_minus\nf98c,f048d,server_network\nf98d,f048e,server_network_off\nf98e,f048f,server_off\nf98f,f0490,server_plus\nf990,f0491,server_remove\nf991,f0492,server_security\nf994,f0495,shape_plus\nf995,f0496,share\nf996,f0497,share_variant\nf997,f0498,shield\nf998,f0499,shield_outline\nf999,f049a,shopping\nf99a,f049b,shopping_music\nf99b,f049c,shredder\nf99c,f049d,shuffle\nf99d,f049e,shuffle_disabled\nf99e,f049f,shuffle_variant\nf99f,f04a0,sigma\nf9a0,f04a1,sign_caution\nf9a1,f04a2,signal\nf9a2,f04a3,silverware\nf9a3,f04a4,silverware_fork\nf9a4,f04a5,silverware_spoon\nf9a5,f04a6,silverware_variant\nf9a6,f04a7,sim\nf9a7,f04a8,sim_alert\nf9a8,f04a9,sim_off\nf9a9,f04aa,sitemap\nf9aa,f04ab,skip_backward\nf9ab,f04ac,skip_forward\nf9ac,f04ad,skip_next\nf9ad,f04ae,skip_previous\nf9ae,f04af,skype\nf9af,f04b0,skype_business\nf9b0,f04b1,slack\nf9b1,f04b2,sleep\nf9b2,f04b3,sleep_off\nf9b3,f04b4,smoking\nf9b4,f04b5,smoking_off\nf9b5,f04b6,snapchat\nf9b6,f04b7,snowman\nf9b7,f04b8,soccer\nf9b8,f04b9,sofa\nf9b9,f04ba,sort\nf9bb,f04bc,sort_ascending\nf9bc,f04bd,sort_descending\nf9be,f04bf,sort_variant\nf9bf,f04c0,soundcloud\nf9c0,f04c1,source_fork\nf9c1,f04c2,source_pull\nf9c2,f04c3,speaker\nf9c3,f04c4,speaker_off\nf9c4,f04c5,speedometer\nf9c5,f04c6,spellcheck\nf9c6,f04c7,spotify\nf9c7,f04c8,spotlight\nf9c8,f04c9,spotlight_beam\nf9cb,f04cc,stack_overflow\nf9cc,f04cd,stairs\nf9cd,f04ce,star\nf9ce,f04cf,star_circle\nf9cf,f0246,star_half\nf9d0,f04d1,star_off\nf9d1,f04d2,star_outline\nf9d2,f04d3,steam\nf9d3,f04d4,steering\nf9d4,f04d5,step_backward\nf9d5,f04d6,step_backward_2\nf9d6,f04d7,step_forward\nf9d7,f04d8,step_forward_2\nf9d8,f04d9,stethoscope\nf9d9,f04da,stocking\nf9da,f04db,stop\nf9db,f04dc,store\nf9dc,f04dd,store_24_hour\nf9dd,f04de,stove\nf9de,f04df,subway_variant\nf9df,f04e0,sunglasses\nf9e0,f04e1,swap_horizontal\nf9e1,f04e2,swap_vertical\nf9e2,f04e3,swim\nf9e3,f04e4,switch\nf9e4,f04e5,sword\nf9e5,f04e6,sync\nf9e6,f04e7,sync_alert\nf9e7,f04e8,sync_off\nf9e8,f04e9,tab\nf9e9,f04ea,tab_unselected\nf9ea,f04eb,table\nf9eb,f04ec,table_column_plus_after\nf9ec,f04ed,table_column_plus_before\nf9ed,f04ee,table_column_remove\nf9ee,f04ef,table_column_width\nf9ef,f04f0,table_edit\nf9f0,f04f1,table_large\nf9f1,f04f2,table_row_height\nf9f2,f04f3,table_row_plus_after\nf9f3,f04f4,table_row_plus_before\nf9f4,f04f5,table_row_remove\nf9f5,f04f6,tablet\nf9f6,f04f7,tablet_android\nf9f8,f04f9,tag\nf9f9,f04fa,tag_faces\nf9fa,f04fb,tag_multiple\nf9fb,f04fc,tag_outline\nf9fc,f04fd,tag_text_outline\nf9fd,f04fe,target\nf9fe,f04ff,taxi\nf9ff,f0500,teamviewer\nfa01,f0502,television\nfa02,f0503,television_guide\nfa03,f0504,temperature_celsius\nfa04,f0505,temperature_fahrenheit\nfa05,f0506,temperature_kelvin\nfa06,f0da0,tennis\nfa07,f0508,tent\nfa09,f050a,text_to_speech\nfa0a,f050b,text_to_speech_off\nfa0b,f050c,texture\nfa0c,f050d,theater\nfa0d,f050e,theme_light_dark\nfa0e,f050f,thermometer\nfa0f,f0510,thermometer_lines\nfa10,f0511,thumb_down\nfa11,f0512,thumb_down_outline\nfa12,f0513,thumb_up\nfa13,f0514,thumb_up_outline\nfa14,f0515,thumbs_up_down\nfa15,f0516,ticket\nfa16,f0517,ticket_account\nfa17,f0518,ticket_confirmation\nfa18,f0519,tie\nfa19,f051a,timelapse\nfa1a,f13ab,timer\nfa1b,f051c,timer_10\nfa1c,f051d,timer_3\nfa1d,f13ac,timer_off\nfa1e,f051f,timer_sand\nfa1f,f0520,timetable\nfa20,f0521,toggle_switch\nfa21,f0522,toggle_switch_off\nfa22,f0523,tooltip\nfa23,f0524,tooltip_edit\nfa24,f0525,tooltip_image\nfa25,f0526,tooltip_outline\nfa27,f0528,tooltip_text\nfa28,f08c3,tooth\nfa2a,f052b,traffic_light\nfa2b,f052c,train\nfa2c,f052d,tram\nfa2d,f052e,transcribe\nfa2e,f052f,transcribe_close\nfa2f,f1065,transfer\nfa30,f0531,tree\nfa31,f0532,trello\nfa32,f0533,trending_down\nfa33,f0534,trending_neutral\nfa34,f0535,trending_up\nfa35,f0536,triangle\nfa36,f0537,triangle_outline\nfa37,f0538,trophy\nfa38,f0539,trophy_award\nfa39,f053a,trophy_outline\nfa3a,f053b,trophy_variant\nfa3b,f053c,trophy_variant_outline\nfa3c,f053d,truck\nfa3d,f053e,truck_delivery\nfa3e,f0a7b,tshirt_crew\nfa3f,f0a7c,tshirt_v\nfa42,f0543,twitch\nfa43,f0544,twitter\nfa47,f0548,ubuntu\nfa48,f0549,umbraco\nfa49,f054a,umbrella\nfa4a,f054b,umbrella_outline\nfa4b,f054c,undo\nfa4c,f054d,undo_variant\nfa4d,f054e,unfold_less_horizontal\nfa4e,f054f,unfold_more_horizontal\nfa4f,f0550,ungroup\nfa51,f0552,upload\nfa52,f0553,usb\nfa53,f0554,vector_arrange_above\nfa54,f0555,vector_arrange_below\nfa55,f0556,vector_circle\nfa56,f0557,vector_circle_variant\nfa57,f0558,vector_combine\nfa58,f0559,vector_curve\nfa59,f055a,vector_difference\nfa5a,f055b,vector_difference_ab\nfa5b,f055c,vector_difference_ba\nfa5c,f055d,vector_intersection\nfa5d,f055e,vector_line\nfa5e,f055f,vector_point\nfa5f,f0560,vector_polygon\nfa60,f0561,vector_polyline\nfa61,f0562,vector_selection\nfa62,f0563,vector_triangle\nfa63,f0564,vector_union\nfa65,f0566,vibrate\nfa66,f0567,video\nfa67,f0568,video_off\nfa68,f0569,video_switch\nfa69,f056a,view_agenda\nfa6a,f056b,view_array\nfa6b,f056c,view_carousel\nfa6c,f056d,view_column\nfa6d,f056e,view_dashboard\nfa6e,f056f,view_day\nfa6f,f0570,view_grid\nfa70,f0571,view_headline\nfa71,f0572,view_list\nfa72,f0573,view_module\nfa73,f0574,view_quilt\nfa74,f0575,view_stream\nfa75,f0576,view_week\nfa76,f0577,vimeo\nfa7b,f057c,vlc\nfa7c,f057d,voicemail\nfa7d,f057e,volume_high\nfa7e,f057f,volume_low\nfa7f,f0580,volume_medium\nfa80,f0581,volume_off\nfa81,f0582,vpn\nfa82,f0583,walk\nfa83,f0584,wallet\nfa84,f0585,wallet_giftcard\nfa85,f0586,wallet_membership\nfa86,f0587,wallet_travel\nfa87,f0588,wan\nfa88,f0589,watch\nfa89,f058a,watch_export\nfa8a,f058b,watch_import\nfa8b,f058c,water\nfa8c,f058d,water_off\nfa8d,f058e,water_percent\nfa8e,f058f,water_pump\nfa8f,f0590,weather_cloudy\nfa90,f0591,weather_fog\nfa91,f0592,weather_hail\nfa92,f0593,weather_lightning\nfa93,f0594,weather_night\nfa95,f0596,weather_pouring\nfa96,f0597,weather_rainy\nfa97,f0598,weather_snowy\nfa98,f0599,weather_sunny\nfa99,f059a,weather_sunset\nfa9a,f059b,weather_sunset_down\nfa9b,f059c,weather_sunset_up\nfa9c,f059d,weather_windy\nfa9d,f059e,weather_windy_variant\nfa9e,f059f,web\nfa9f,f05a0,webcam\nfaa0,f05a1,weight\nfaa1,f05a2,weight_kilogram\nfaa2,f05a3,whatsapp\nfaa3,f05a4,wheelchair_accessibility\nfaa4,f05a5,white_balance_auto\nfaa5,f05a6,white_balance_incandescent\nfaa6,f05a7,white_balance_iridescent\nfaa7,f05a8,white_balance_sunny\nfaa8,f05a9,wifi\nfaa9,f05aa,wifi_off\nfaab,f05ac,wikipedia\nfaac,f05ad,window_close\nfaad,f05ae,window_closed\nfaae,f05af,window_maximize\nfaaf,f05b0,window_minimize\nfab0,f05b1,window_open\nfab1,f05b2,window_restore\nfab3,f05b4,wordpress\nfab5,f05b6,wrap\nfab6,f05b7,wrench\nfabf,f05c0,xml\nfac0,f05c1,yeast\nfac3,f05c4,zip_box\nfac4,f05c5,surround_sound\nfac5,f05c6,vector_rectangle\nfac6,f05c7,playlist_check\nfac7,f05c8,format_line_style\nfac8,f05c9,format_line_weight\nfac9,f05ca,translate\nfacb,f05cc,opacity\nfacc,f18f0,near_me\nfacd,f0955,clock_alert\nface,f05cf,human_pregnant\nfacf,f1364,sticker\nfad0,f05d1,scale_balance\nfad2,f05d3,account_multiple_minus\nfad3,f05d4,airplane_landing\nfad4,f05d5,airplane_takeoff\nfad5,f05d6,alert_circle_outline\nfad6,f05d7,altimeter\nfad7,f05d8,animation\nfad8,f05d9,book_minus\nfad9,f05da,book_open_page_variant\nfada,f05db,book_plus\nfadb,f05dc,boombox\nfadc,f05dd,bullseye\nfadd,f05de,comment_remove\nfade,f05df,camera_off\nfadf,f05e0,check_circle\nfae0,f05e1,check_circle_outline\nfae1,f05e2,candle\nfae2,f05e3,chart_bubble\nfae3,f0ff1,credit_card_off\nfae4,f05e5,cup_off\nfae5,f05e6,copyright\nfae6,f05e7,cursor_text\nfae7,f05e8,delete_forever\nfae8,f05e9,delete_sweep\nfae9,f1155,dice_d20\nfaea,f1150,dice_d4\nfaeb,f1151,dice_d6\nfaec,f1152,dice_d8\nfaee,f05ef,email_open_outline\nfaef,f05f0,email_variant\nfaf0,f05f1,ev_station\nfaf1,f05f2,food_fork_drink\nfaf2,f05f3,food_off\nfaf3,f05f4,format_title\nfaf4,f05f5,google_maps\nfaf5,f05f6,heart_pulse\nfaf6,f05f7,highway\nfaf7,f05f8,home_map_marker\nfaf8,f05f9,incognito\nfaf9,f05fa,kettle\nfafa,f05fb,lock_plus\nfafc,f05fd,logout_variant\nfafd,f05fe,music_note_bluetooth\nfafe,f05ff,music_note_bluetooth_off\nfaff,f0600,page_first\nfb00,f0601,page_last\nfb01,f0602,phone_classic\nfb02,f0603,priority_high\nfb03,f0604,priority_low\nfb04,f0605,qqchat\nfb05,f0606,pool\nfb06,f0607,rounded_corner\nfb07,f0608,rowing\nfb08,f0609,saxophone\nfb09,f060a,signal_variant\nfb0b,f060c,subdirectory_arrow_left\nfb0c,f060d,subdirectory_arrow_right\nfb0e,f060f,violin\nfb10,f0611,wechat\nfb11,f0612,watermark\nfb12,f0613,file_hidden\nfb13,f08c6,application\nfb14,f0615,arrow_collapse\nfb15,f0616,arrow_expand\nfb16,f028e,bowl\nfb17,f0618,bridge\nfb19,f061a,chip\nfb1a,f061b,content_save_settings\nfb1b,f061c,dialpad\nfb1d,f061e,format_horizontal_align_center\nfb1e,f061f,format_horizontal_align_left\nfb1f,f0620,format_horizontal_align_right\nfb20,f0621,format_vertical_align_bottom\nfb21,f0622,format_vertical_align_center\nfb22,f0623,format_vertical_align_top\nfb24,f0625,help_circle_outline\nfb26,f0627,lambda\nfb27,f0628,matrix\nfb28,f0629,meteor\nfb2a,f062b,sigma_lower\nfb2b,f062c,source_branch\nfb2c,f062d,source_merge\nfb2d,f062e,tune\nfb2e,f062f,webhook\nfb2f,f0630,account_settings\nfb31,f0632,apple_keyboard_caps\nfb32,f0633,apple_keyboard_command\nfb33,f0634,apple_keyboard_control\nfb34,f0635,apple_keyboard_option\nfb35,f0636,apple_keyboard_shift\nfb36,f0637,box_shadow\nfb37,f0638,cards\nfb38,f0639,cards_outline\nfb39,f063a,cards_playing_outline\nfb3a,f063b,checkbox_multiple_blank_circle\nfb3b,f063c,checkbox_multiple_blank_circle_outline\nfb3c,f063d,checkbox_multiple_marked_circle\nfb3d,f063e,checkbox_multiple_marked_circle_outline\nfb3e,f063f,cloud_sync\nfb3f,f0640,collage\nfb40,f0641,directions_fork\nfb41,f0642,eraser_variant\nfb44,f0645,file_tree\nfb45,f0646,format_annotation_plus\nfb46,f0647,gas_cylinder\nfb47,f0648,grease_pencil\nfb48,f0649,human_female\nfb49,f17c4,human_greeting\nfb4a,f064b,human_handsdown\nfb4b,f064c,human_handsup\nfb4c,f064d,human_male\nfb4d,f064e,information_variant\nfb4e,f064f,lead_pencil\nfb4f,f0650,map_marker_minus\nfb50,f0651,map_marker_plus\nfb51,f0652,marker\nfb52,f0653,message_plus\nfb53,f0654,microscope\nfb54,f0655,move_resize\nfb55,f0656,move_resize_variant\nfb56,f0657,paw_off\nfb57,f0658,phone_minus\nfb58,f0659,phone_plus\nfb59,f02e5,pot\nfb5a,f065b,pot_mix\nfb5b,f065c,serial_port\nfb5c,f065d,shape_circle_plus\nfb5d,f065e,shape_polygon_plus\nfb5e,f065f,shape_rectangle_plus\nfb5f,f0660,shape_square_plus\nfb60,f0661,skip_next_circle\nfb61,f0662,skip_next_circle_outline\nfb62,f0663,skip_previous_circle\nfb63,f0664,skip_previous_circle_outline\nfb64,f0665,spray\nfb65,f0666,stop_circle\nfb66,f0667,stop_circle_outline\nfb67,f0668,test_tube\nfb68,f0669,text_shadow\nfb69,f066a,tune_vertical\nfb6a,f066b,cart_off\nfb6b,f066c,chart_gantt\nfb6d,f066e,chart_timeline\nfb6e,f066f,discord\nfb6f,f0670,file_restore\nfb70,f0671,language_c\nfb71,f0672,language_cpp\nfb74,f0ff2,credit_card_plus\nfb76,f0678,bow_tie\nfb77,f0679,calendar_range\nfb78,f067a,currency_usd_off\nfb79,f067b,flash_red_eye\nfb7a,f067c,oar\nfb7b,f067d,piano\nfb7c,f067e,weather_lightning_rainy\nfb7d,f067f,weather_snowy_rainy\nfb7e,f0680,yin_yang\nfb7f,f0681,tower_beach\nfb80,f0682,tower_fire\nfb81,f0683,delete_circle\nfb82,f0684,dna\nfb83,f0685,hamburger\nfb84,f0686,gondola\nfb85,f0687,inbox\nfb86,f0688,reorder_horizontal\nfb87,f0689,reorder_vertical\nfb89,f068b,tag_heart\nfb8a,f068c,skull\nfb8b,f068d,solid\nfb8c,f068e,alarm_snooze\nfb8d,f13e0,baby_buggy\nfb8e,f0cea,beaker\nfb8f,f0691,bomb\nfb90,f0692,calendar_question\nfb91,f0693,camera_burst\nfb92,f0694,code_tags_check\nfb94,f0696,crop_rotate\nfb95,f0697,developer_board\nfb99,f0c6e,emoticon_dead\nfb9a,f0c70,emoticon_excited\nfb9b,f069d,folder_star\nfb9c,f069e,format_color_text\nfb9d,f069f,format_section\nfb9f,f06a1,home_outline\nfba0,f06a2,message_bulleted\nfba1,f06a3,message_bulleted_off\nfba2,f06a4,nuke\nfba3,f06a5,power_plug\nfba4,f06a6,power_plug_off\nfba5,f06a7,publish\nfba6,f099b,restore\nfba7,f06a9,robot\nfba8,f06aa,format_rotate_90\nfba9,f06ab,scanner\nfbaa,f06ac,subway\nfbab,f06ad,timer_sand_empty\nfbac,f06ae,transit_transfer\nfbad,f06af,unity\nfbae,f06b0,update\nfbaf,f06b1,watch_vibrate\nfbb0,f06b2,angular\nfbb1,f06b3,dolby\nfbb2,f06b4,emby\nfbb3,f06b5,lamp\nfbb4,f06b6,menu_down_outline\nfbb5,f06b7,menu_up_outline\nfbb6,f06b8,note_multiple\nfbb7,f06b9,note_multiple_outline\nfbb8,f06ba,plex\nfbba,f06bc,account_edit\nfbbb,f06bd,alert_decagram\nfbbc,f06be,all_inclusive\nfbbd,f06bf,angularjs\nfbbe,f06c0,arrow_down_box\nfbbf,f06c1,arrow_left_box\nfbc0,f06c2,arrow_right_box\nfbc1,f06c3,arrow_up_box\nfbc2,f06c4,asterisk\nfbc3,f06c5,bomb_off\nfbc4,f06c6,bootstrap\nfbc5,f06c7,cards_variant\nfbc6,f06c8,clipboard_flow\nfbc7,f06c9,close_outline\nfbc8,f06ca,coffee_outline\nfbc9,f06cb,contacts\nfbca,f06cc,delete_empty\nfbcb,f06cd,earth_box\nfbcc,f06ce,earth_box_off\nfbcd,f06cf,email_alert\nfbce,f06d0,eye_outline\nfbcf,f06d1,eye_off_outline\nfbd0,f06d2,fast_forward_outline\nfbd1,f06d3,feather\nfbd2,f06d4,find_replace\nfbd3,f06d5,flash_outline\nfbd4,f06d6,format_font\nfbd5,f06d7,format_page_break\nfbd6,f06d8,format_pilcrow\nfbd7,f06d9,garage\nfbd8,f06da,garage_open\nfbda,f06dc,google_keep\nfbdc,f06de,heart_half_full\nfbdd,f06df,heart_half\nfbde,f06e0,heart_half_outline\nfbdf,f06e1,hexagon_multiple\nfbe0,f06e2,hook\nfbe1,f06e3,hook_off\nfbe2,f06e4,infinity\nfbe3,f06e5,language_swift\nfbe4,f06e6,language_typescript\nfbe5,f06e7,laptop_off\nfbe6,f06e8,lightbulb_on\nfbe7,f06e9,lightbulb_on_outline\nfbe8,f06ea,lock_pattern\nfbea,f06ec,magnify_minus_outline\nfbeb,f06ed,magnify_plus_outline\nfbec,f06ee,mailbox\nfbed,f06ef,medical_bag\nfbee,f06f0,message_settings\nfbf0,f06f2,minus_box_outline\nfbf1,f06f3,network\nfbf2,f06f4,download_network\nfbf3,f06f5,help_network\nfbf4,f06f6,upload_network\nfbf5,f06f7,npm\nfbf6,f06f8,nut\nfbf7,f06f9,octagram\nfbf8,f06fa,page_layout_body\nfbf9,f06fb,page_layout_footer\nfbfa,f06fc,page_layout_header\nfbfb,f06fd,page_layout_sidebar_left\nfbfc,f06fe,page_layout_sidebar_right\nfbfd,f06ff,pencil_circle\nfbfe,f0701,pentagon\nfbff,f0700,pentagon_outline\nfc00,f0702,pillar\nfc01,f0703,pistol\nfc02,f0704,plus_box_outline\nfc03,f0705,plus_outline\nfc04,f0706,prescription\nfc05,f0707,printer_settings\nfc06,f0708,react\nfc07,f0709,restart\nfc08,f070a,rewind_outline\nfc09,f070b,rhombus\nfc0a,f070c,rhombus_outline\nfc0c,f070e,run\nfc0d,f070f,search_web\nfc0e,f0710,shovel\nfc0f,f0711,shovel_off\nfc10,f0712,signal_2g\nfc11,f0713,signal_3g\nfc12,f0714,signal_4g\nfc13,f0715,signal_hspa\nfc14,f0716,signal_hspa_plus\nfc15,f0717,snowflake\nfc16,f0718,source_commit\nfc17,f0719,source_commit_end\nfc18,f071a,source_commit_end_local\nfc19,f071b,source_commit_local\nfc1a,f071c,source_commit_next_local\nfc1b,f071d,source_commit_start\nfc1c,f071e,source_commit_start_next_local\nfc1d,f071f,speaker_wireless\nfc1e,f0ff9,stadium\nfc1f,f0721,svg\nfc20,f0722,tag_plus\nfc21,f0723,tag_remove\nfc22,f0724,ticket_percent\nfc23,f0725,tilde\nfc24,f0726,treasure_chest\nfc25,f0727,truck_trailer\nfc26,f0728,view_parallel\nfc27,f0729,view_sequential\nfc28,f072a,washing_machine\nfc29,f072b,webpack\nfc2a,f072c,widgets\nfc2c,f072e,arrow_down_bold\nfc2d,f072f,arrow_down_bold_box\nfc2e,f0730,arrow_down_bold_box_outline\nfc2f,f0731,arrow_left_bold\nfc30,f0732,arrow_left_bold_box\nfc31,f0733,arrow_left_bold_box_outline\nfc32,f0734,arrow_right_bold\nfc33,f0735,arrow_right_bold_box\nfc34,f0736,arrow_right_bold_box_outline\nfc35,f0737,arrow_up_bold\nfc36,f0738,arrow_up_bold_box\nfc37,f0739,arrow_up_bold_box_outline\nfc38,f073a,cancel\nfc39,f073b,file_account\nfc3a,f073c,gesture_double_tap\nfc3b,f073d,gesture_swipe_down\nfc3c,f073e,gesture_swipe_left\nfc3d,f073f,gesture_swipe_right\nfc3e,f0740,gesture_swipe_up\nfc3f,f0741,gesture_tap\nfc40,f0742,gesture_two_double_tap\nfc41,f0743,gesture_two_tap\nfc42,f0744,humble_bundle\nfc43,f0745,kickstarter\nfc44,f0746,netflix\nfc48,f074a,vector_radius\nfc4f,f0751,clipboard_plus\nfc50,f0752,file_plus\nfc51,f0753,format_align_bottom\nfc52,f0754,format_align_middle\nfc53,f0755,format_align_top\nfc54,f0756,format_list_checks\nfc55,f0757,format_quote_open\nfc56,f0758,grid_large\nfc57,f0759,heart_off\nfc58,f075a,music\nfc59,f075b,music_off\nfc5a,f075c,tab_plus\nfc5b,f075d,volume_plus\nfc5c,f075e,volume_minus\nfc5d,f075f,volume_mute\nfc5e,f0760,unfold_less_vertical\nfc5f,f0761,unfold_more_vertical\nfc60,f0762,taco\nfc61,f0763,square_outline\nfc62,f0764,square\nfc65,f0767,alert_octagram\nfc66,f0768,atom\nfc67,f0769,ceiling_light\nfc68,f076a,chart_bar_stacked\nfc69,f076b,chart_line_stacked\nfc6a,f076c,decagram\nfc6b,f076d,decagram_outline\nfc6c,f076e,dice_multiple\nfc6d,f1153,dice_d10\nfc6e,f0770,folder_open\nfc6f,f0771,guitar_acoustic\nfc70,f0772,loading\nfc71,f0773,lock_reset\nfc72,f0774,ninja\nfc73,f0775,octagram_outline\nfc74,f0776,pencil_circle_outline\nfc75,f0777,selection_off\nfc76,f0778,set_all\nfc77,f0779,set_center\nfc78,f077a,set_center_right\nfc79,f077b,set_left\nfc7a,f077c,set_left_center\nfc7b,f077d,set_left_right\nfc7c,f077e,set_none\nfc7d,f077f,set_right\nfc7e,f0780,shield_half_full\nfc7f,f0781,sign_direction\nfc80,f0782,sign_text\nfc81,f0783,signal_off\nfc82,f0784,square_root\nfc83,f0785,sticker_emoji\nfc84,f0786,summit\nfc85,f0787,sword_cross\nfc86,f0788,truck_fast\nfc88,f078a,cast_off\nfc89,f078b,help_box\nfc8a,f078c,timer_sand_full\nfc8b,f078d,waves\nfc8c,f078e,alarm_bell\nfc8d,f078f,alarm_light\nfc90,f0792,arrow_collapse_down\nfc91,f0793,arrow_collapse_left\nfc92,f0794,arrow_collapse_right\nfc93,f0795,arrow_collapse_up\nfc94,f0796,arrow_expand_down\nfc95,f0797,arrow_expand_left\nfc96,f0798,arrow_expand_right\nfc97,f0799,arrow_expand_up\nfc9a,f079c,bus_articulated_end\nfc9b,f079d,bus_articulated_front\nfc9c,f079e,bus_double_decker\nfc9d,f079f,bus_school\nfc9e,f07a0,bus_side\nfc9f,f07a1,camera_gopro\nfca0,f07a2,camera_metering_center\nfca1,f07a3,camera_metering_matrix\nfca2,f07a4,camera_metering_partial\nfca3,f07a5,camera_metering_spot\nfca4,f07a6,cannabis\nfca5,f07a7,car_convertible\nfca6,f07a8,car_estate\nfca7,f07a9,car_hatchback\nfca8,f07aa,car_pickup\nfca9,f07ab,car_side\nfcaa,f07ac,car_sports\nfcab,f07ad,caravan\nfcac,f07ae,cctv\nfcad,f07af,chart_donut\nfcae,f07b0,chart_donut_variant\nfcaf,f07b1,chart_line_variant\nfcb0,f07b2,chili_hot\nfcb1,f07b3,chili_medium\nfcb2,f07b4,chili_mild\nfcb3,f07b5,cloud_braces\nfcb4,f07b6,cloud_tags\nfcb5,f07b7,console_line\nfcb6,f07b8,corn\nfcb8,f07ba,currency_cny\nfcb9,f07bb,currency_eth\nfcba,f07bc,currency_jpy\nfcbb,f07bd,currency_krw\nfcbc,f07be,currency_sign\nfcbd,f07bf,currency_twd\nfcbe,f07c0,desktop_classic\nfcbf,f07c1,dip_switch\nfcc0,f07c2,donkey\nfcc1,f07c3,dots_horizontal_circle\nfcc2,f07c4,dots_vertical_circle\nfcc3,f07c5,ear_hearing\nfcc4,f07c6,elephant\nfcc6,f07c8,food_croissant\nfcc7,f07c9,forklift\nfcc8,f07ca,fuel\nfcc9,f07cb,gesture\nfcca,f07cc,google_analytics\nfccb,f07cd,google_assistant\nfccc,f07ce,headphones_off\nfccd,f07cf,high_definition\nfcce,f07d0,home_assistant\nfccf,f07d1,home_automation\nfcd0,f07d2,home_circle\nfcd1,f07d3,language_go\nfcd2,f07d4,language_r\nfcd3,f07d5,lava_lamp\nfcd4,f07d6,led_strip\nfcd5,f07d7,locker\nfcd6,f07d8,locker_multiple\nfcd7,f07d9,map_marker_outline\nfcd8,f07da,metronome\nfcd9,f07db,metronome_tick\nfcda,f07dc,micro_sd\nfcdc,f07de,movie_roll\nfcdd,f07df,mushroom\nfcde,f07e0,mushroom_outline\nfcdf,f07e1,nintendo_switch\nfce0,f07e2,null\nfce1,f07e3,passport\nfce3,f07e5,pipe\nfce4,f07e6,pipe_disconnected\nfce5,f07e7,power_socket_eu\nfce6,f07e8,power_socket_uk\nfce7,f07e9,power_socket_us\nfce8,f07ea,rice\nfce9,f07eb,ring\nfcea,f07ec,sass\nfcec,f07ee,soy_sauce\nfced,f07ef,standard_definition\nfcee,f07f0,surround_sound_2_0\nfcef,f07f1,surround_sound_3_1\nfcf0,f07f2,surround_sound_5_1\nfcf1,f07f3,surround_sound_7_1\nfcf2,f07f4,television_classic\nfcf4,f07f6,thought_bubble\nfcf5,f07f7,thought_bubble_outline\nfcf6,f07f8,trackpad\nfcf7,f07f9,ultra_high_definition\nfcf8,f07fa,van_passenger\nfcf9,f07fb,van_utility\nfcfa,f07fc,vanish\nfcfb,f07fd,video_3d\nfcfc,f07fe,wall\nfcfd,f07ff,xmpp\nfcfe,f0800,account_multiple_plus_outline\nfcff,f0801,account_plus_outline\nfd02,f0804,atlassian\nfd04,f0806,basketball\nfd05,f0807,battery_charging_wireless\nfd06,f0808,battery_charging_wireless_10\nfd07,f0809,battery_charging_wireless_20\nfd08,f080a,battery_charging_wireless_30\nfd09,f080b,battery_charging_wireless_40\nfd0a,f080c,battery_charging_wireless_50\nfd0b,f080d,battery_charging_wireless_60\nfd0c,f080e,battery_charging_wireless_70\nfd0d,f080f,battery_charging_wireless_80\nfd0e,f0810,battery_charging_wireless_90\nfd0f,f0811,battery_charging_wireless_alert\nfd10,f0812,battery_charging_wireless_outline\nfd11,f0813,bitcoin\nfd12,f0814,briefcase_outline\nfd13,f0815,cellphone_wireless\nfd14,f0816,clover\nfd15,f0817,comment_question\nfd16,f0818,content_save_outline\nfd17,f0819,delete_restore\nfd18,f081a,door\nfd19,f081b,door_closed\nfd1a,f081c,door_open\nfd1b,f081d,fan_off\nfd1c,f081e,file_percent\nfd1d,f081f,finance\nfd1f,f0821,floor_plan\nfd20,f0822,forum_outline\nfd21,f0823,golf\nfd22,f0824,google_home\nfd23,f0825,guy_fawkes_mask\nfd24,f0826,home_account\nfd25,f0827,home_heart\nfd26,f0828,hot_tub\nfd27,f0829,hulu\nfd28,f082a,ice_cream\nfd29,f082b,image_off\nfd2a,f082c,karate\nfd2b,f082d,ladybug\nfd2c,f082e,notebook\nfd2d,f082f,phone_return\nfd2e,f0830,poker_chip\nfd2f,f0831,shape\nfd30,f0832,shape_outline\nfd31,f0833,ship_wheel\nfd32,f0834,soccer_field\nfd33,f0835,table_column\nfd34,f0836,table_of_contents\nfd35,f0837,table_row\nfd36,f0838,table_settings\nfd37,f0839,television_box\nfd38,f083a,television_classic_off\nfd39,f083b,television_off\nfd3b,f083d,upload_multiple\nfd3c,f083e,video_4k_box\nfd3d,f083f,video_input_antenna\nfd3e,f0840,video_input_component\nfd3f,f0841,video_input_hdmi\nfd40,f0842,video_input_svideo\nfd41,f0843,view_dashboard_variant\nfd42,f0844,vuejs\nfd43,f0845,xamarin\nfd46,f0848,youtube_gaming\n"
  },
  {
    "path": "website/static/img/themes/.keep",
    "content": ""
  },
  {
    "path": "website/static/install.ps1",
    "content": "$installInstructions = @'\nHey friend\n\nThis installer is only available for Windows.\nIf you're looking for installation instructions for your operating system,\nplease visit the following link:\n'@\nif ($IsMacOS) {\n    Write-Host @\"\n$installInstructions\n\nhttps://ohmyposh.dev/docs/installation/macos\n\"@\n    exit\n}\nif ($IsLinux) {\n    Write-Host @\"\n$installInstructions\n\nhttps://ohmyposh.dev/docs/installation/linux\n\"@\n    exit\n}\n\n$installer = ''\n$arch = (Get-CimInstance -Class Win32_Processor -Property Architecture).Architecture | Select-Object -First 1\nswitch ($arch) {\n    5 { $installer = \"install-arm64.msix\" } # ARM64\n    9 {\n        if ([Environment]::Is64BitOperatingSystem) {\n            $installer = \"install-x64.msix\"\n        }\n        else {\n            Write-Host \"MSIX installer is only available for x64 and ARM64 architectures.\"\n            exit\n        }\n    }\n    12 { $installer = \"install-arm64.msix\" } # ARM64 Surface Pro X\n    default {\n        Write-Host \"MSIX installer is only available for x64 and ARM64 architectures.\"\n        exit\n    }\n}\n\nWrite-Host \"Downloading $installer...\"\n\n# validate the availability of New-TemporaryFile\nif (Get-Command -Name New-TemporaryFile -ErrorAction SilentlyContinue) {\n    $tmp = New-TemporaryFile | Rename-Item -NewName { $_ -replace 'tmp$', 'msix' } -PassThru\n}\nelse {\n    $tmp = New-Item -Path $env:TEMP -Name ([System.IO.Path]::GetRandomFileName() -replace '\\.\\w+$', '.msix') -Force -ItemType File\n}\n$url = \"https://cdn.ohmyposh.dev/releases/latest/$installer\"\n\n# check if we can make https requests and download the binary\ntry {\n    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12\n    Invoke-WebRequest -Uri $url -Method Head | Where-Object -FilterScript { $_.StatusCode -ne 200 }  # Suppress success output\n}\ncatch {\n    Write-Host \"Unable to download $installer. Please check your internet connection.\"\n    exit\n}\n\nInvoke-WebRequest -OutFile $tmp $url\nWrite-Host 'Installing MSIX package for current user...'\n\nAdd-AppxPackage -Path $tmp\n\nWrite-Host @'\nDone!\n\nRestart your terminal and have a look at the\ndocumentation on how to proceed from here.\n\nhttps://ohmyposh.dev/docs/installation/prompt\n'@\n"
  },
  {
    "path": "website/static/install.sh",
    "content": "#!/usr/bin/env bash\n\ninstall_dir=\"\"\nthemes_dir=\"\"\nexecutable=\"\"\nversion=\"\"\n\nerror() {\n    printf \"\\e[31m$1\\e[0m\\n\"\n    exit 1\n}\n\ninfo() {\n    printf \"$1\\n\"\n}\n\nwarn() {\n    printf \"⚠️  \\e[33m$1\\e[0m\\n\"\n}\n\nhelp() {\n    # Display Help\n    echo \"Install script for Oh My Posh\"\n    echo\n    echo \"Syntax: install.sh [-h] [-d <dir>] [-t <dir>] [-v <ver>]\"\n    echo \"options:\"\n    echo \"-h     Print this help.\"\n    echo \"-d     Specify the installation directory. Defaults to $HOME/bin, $HOME/.local/bin or the directory where oh-my-posh is installed.\"\n    echo \"-t     Specify the themes installation directory. Defaults to the oh-my-posh cache directory.\"\n    echo \"-v     Version to download, defaults to latest\"\n    echo\n}\n\nwhile getopts \":hd:t:v:\" option; do\n   case $option in\n      h) # display Help\n         help\n         exit;;\n      d) # Enter a name\n         install_dir=${OPTARG};;\n      t) # themes directory\n         themes_dir=${OPTARG};;\n      v) # version\n         version=${OPTARG};;\n     \\?) # Invalid option\n         echo \"Invalid option command line option. Use -h for help.\"\n         exit 1\n   esac\ndone\n\nSUPPORTED_TARGETS=\"linux-amd64 linux-arm linux-arm64 darwin-amd64 darwin-arm64 freebsd-amd64 freebsd-arm freebsd-arm64\"\n\nvalidate_dependency() {\n    if ! command -v $1 >/dev/null; then\n        error \"$1 is required to install Oh My Posh. Please install $1 and try again.\\n\"\n    fi\n}\n\nvalidate_dependencies() {\n    validate_dependency curl\n    validate_dependency unzip\n    validate_dependency realpath\n    validate_dependency dirname\n}\n\nset_install_directory() {\n    if [ -n \"$install_dir\" ]; then\n        # expand directory\n        install_dir=\"${install_dir/#\\~/$HOME}\"\n        return 0\n    fi\n\n    # check if we have oh-my-posh installed, if so, use the executable directory\n    # to install into and follow symlinks\n    if command -v oh-my-posh >/dev/null; then\n        posh_dir=$(command -v oh-my-posh)\n        real_dir=$(realpath $posh_dir)\n        install_dir=$(dirname $real_dir)\n        info \"Oh My Posh is already installed, updating existing installation in:\"\n        info \"  ${install_dir}\"\n        return 0\n    fi\n\n    # check if $HOME/bin exists and is writable\n    if [ -d \"$HOME/bin\" ] && [ -w \"$HOME/bin\" ]; then\n        install_dir=\"$HOME/bin\"\n        return 0\n    fi\n\n    # check if $HOME/.local/bin exists and is writable\n    if ([ -d \"$HOME/.local/bin\" ] && [ -w \"$HOME/.local/bin\" ]) || mkdir -p \"$HOME/.local/bin\"; then\n        install_dir=\"$HOME/.local/bin\"\n        return 0\n    fi\n\n    error \"Cannot determine installation directory. Please specify a directory and try again: \\ncurl -s https://ohmyposh.dev/install.sh | bash -s -- -d {directory}\"\n}\n\nvalidate_install_directory() {\n    #check if installation dir exists\n    if [ ! -d \"$install_dir\" ]; then\n        error \"Directory ${install_dir} does not exist, set a different directory and try again.\"\n    fi\n\n    # Check if regular user has write permission\n    if [ ! -w \"$install_dir\" ]; then\n        error \"Cannot write to ${install_dir}. Please check write permissions or set a different directory and try again: \\ncurl -s https://ohmyposh.dev/install.sh | bash -s -- -d {directory}\"\n    fi\n\n    # check if the directory is in the PATH\n    good=$(\n        IFS=:\n        for path in $PATH; do\n        if [ \"${path%/}\" = \"${install_dir}\" ]; then\n            printf 1\n            break\n        fi\n        done\n    )\n\n    if [ \"${good}\" != \"1\" ]; then\n        warn \"Installation directory ${install_dir} is not in your \\$PATH, add it using \\nexport PATH=\\$PATH:${install_dir}\"\n    fi\n}\n\nvalidate_themes_directory() {\n\n    # Validate if the themes directory exists\n    if ! mkdir -p \"$themes_dir\" > /dev/null 2>&1; then\n        error \"Cannot write to ${themes_dir}. Please check write permissions or set a different directory and try again: \\ncurl -s https://ohmyposh.dev/install.sh | bash -s -- -t {directory}\"\n    fi\n\n    #check user write permission\n    if [ ! -w \"$themes_dir\" ]; then\n        error \"Cannot write to ${themes_dir}. Please check write permissions or set a different directory and try again: \\ncurl -s https://ohmyposh.dev/install.sh | bash -s -- -t {directory}\"\n    fi\n}\n\ninstall_themes() {\n    if [ -n \"$themes_dir\" ]; then\n        # expand directory\n        themes_dir=\"${themes_dir/#\\~/$HOME}\"\n    fi\n\n    cache_dir=$($executable cache path)\n\n    # validate if the user set the path to the themes directory\n    if [ -z \"$themes_dir\" ]; then\n        themes_dir=\"${cache_dir}/themes\"\n    fi\n\n    validate_themes_directory\n\n    info \"🎨 Installing oh-my-posh themes in ${themes_dir}\\n\"\n\n    zip_file=\"${cache_dir}/themes.zip\"\n\n    url=\"https://cdn.ohmyposh.dev/releases/latest/themes.zip\"\n\n    http_response=$(curl -s -f -L $url -o $zip_file -w \"%{http_code}\")\n\n    if [ $http_response = \"200\" ] && [ -f $zip_file ]; then\n        unzip -o -q $zip_file -d $themes_dir\n        # make sure the files are readable and writable for all users\n        chmod a+rwX ${themes_dir}/*.omp.*\n        rm $zip_file\n    else\n        warn \"Unable to download themes at ${url}\\nPlease validate your curl, connection and/or proxy settings\"\n    fi\n}\n\ninstall() {\n    arch=$(detect_arch)\n    platform=$(detect_platform)\n    target=\"${platform}-${arch}\"\n\n    good=$(\n        IFS=\" \"\n        for t in $SUPPORTED_TARGETS; do\n        if [ \"${t}\" = \"${target}\" ]; then\n            printf 1\n            break\n        fi\n        done\n    )\n\n    if [ \"${good}\" != \"1\" ]; then\n        error \"${arch} builds for ${platform} are not available for Oh My Posh\"\n    fi\n\n    info \"\\nℹ️  Installing oh-my-posh for ${target} in ${install_dir}\"\n\n    executable=${install_dir}/oh-my-posh\n    url=https://cdn.ohmyposh.dev/releases/latest/posh-${target}\n    if [ \"$version\" ]; then\n      url=https://cdn.ohmyposh.dev/releases/${version}/posh-${target}\n    fi\n\n    info \"⬇️  Downloading oh-my-posh from ${url}\"\n\n    http_response=$(curl -s -f -L $url -o $executable -w \"%{http_code}\")\n\n    if [ $http_response != \"200\" ] || [ ! -f $executable ]; then\n        error \"Unable to download executable at ${url}\\nPlease validate your curl, connection and/or proxy settings\"\n    fi\n\n    chmod +x $executable\n\n    install_themes\n\n    info \"🚀 Installation complete.\\n\\nYou can follow the instructions at https://ohmyposh.dev/docs/installation/prompt\"\n    info \"to setup your shell to use oh-my-posh.\"\n    if [ $http_response = \"200\" ]; then\n        info \"\\nIf you want to use a built-in theme, you can find them in the ${themes_dir} directory:\"\n        info \"  oh-my-posh init {shell} --config ${themes_dir}/{theme}.omp.json\\n\"\n    fi\n}\n\ndetect_arch() {\n  arch=\"$(uname -m | tr '[:upper:]' '[:lower:]')\"\n\n  case \"${arch}\" in\n    x86_64) arch=\"amd64\" ;;\n    armv*) arch=\"arm\" ;;\n    arm64) arch=\"arm64\" ;;\n    aarch64) arch=\"arm64\" ;;\n  esac\n\n  if [ \"${arch}\" = \"arm64\" ] && [ \"$(getconf LONG_BIT)\" -eq 32 ]; then\n    arch=arm\n  fi\n\n  printf '%s' \"${arch}\"\n}\n\n\ndetect_platform() {\n  platform=\"$(uname -s | awk '{print tolower($0)}')\"\n\n  case \"${platform}\" in\n    linux) platform=\"linux\" ;;\n    darwin) platform=\"darwin\" ;;\n  esac\n\n  printf '%s' \"${platform}\"\n}\n\nvalidate_dependencies\nset_install_directory\nvalidate_install_directory\ninstall\n"
  },
  {
    "path": "website/staticwebapp.config.json",
    "content": "{\n  \"platform\": {\n    \"apiRuntime\": \"node:20\"\n  }\n}\n"
  }
]