Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package typioca for openSUSE:Factory checked 
in at 2024-07-18 19:19:25
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/typioca (Old)
 and      /work/SRC/openSUSE:Factory/.typioca.new.17339 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "typioca"

Thu Jul 18 19:19:25 2024 rev:2 rq:1188253 version:3.0.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/typioca/typioca.changes  2024-06-17 
19:28:40.556455802 +0200
+++ /work/SRC/openSUSE:Factory/.typioca.new.17339/typioca.changes       
2024-07-18 19:19:27.318563154 +0200
@@ -1,0 +2,11 @@
+Wed Jul 17 18:27:21 UTC 2024 - [email protected]
+
+- Update to version 3.0.0:
+  * chore: bump dependencies
+  * Bump golang.org/x/term from 0.18.0 to 0.22.0 (#157)
+  * Bump github.com/charmbracelet/bubbletea from 0.25.0 to 0.26.6 (#152)
+  * feat: add Dvorak emulation layout (#156)
+  * Add keyboard layout emulation (#154)
+  * add openSUSE install instruction
+
+-------------------------------------------------------------------

Old:
----
  typioca-2.11.2.tar.gz

New:
----
  typioca-3.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ typioca.spec ++++++
--- /var/tmp/diff_new_pack.XMqF2T/_old  2024-07-18 19:19:28.254600619 +0200
+++ /var/tmp/diff_new_pack.XMqF2T/_new  2024-07-18 19:19:28.254600619 +0200
@@ -17,8 +17,8 @@
 
 
 Name:           typioca
-Version:        2.11.2
-Release:        1
+Version:        3.0.0
+Release:        0
 Summary:        Minimal terminal based typing speed tester
 License:        MIT
 Group:          Productivity/Text/Utilities

++++++ _service ++++++
--- /var/tmp/diff_new_pack.XMqF2T/_old  2024-07-18 19:19:28.286601900 +0200
+++ /var/tmp/diff_new_pack.XMqF2T/_new  2024-07-18 19:19:28.290602060 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/bloznelis/typioca.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">2.11.2</param>
+    <param name="revision">3.0.0</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="changesgenerate">enable</param>
     <param name="versionrewrite-pattern">v(.*)</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.XMqF2T/_old  2024-07-18 19:19:28.310602861 +0200
+++ /var/tmp/diff_new_pack.XMqF2T/_new  2024-07-18 19:19:28.314603021 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/bloznelis/typioca.git</param>
-              <param 
name="changesrevision">1c6a0ac60a1ab27784d12c4f25cb4bd2231204c9</param></service></servicedata>
+              <param 
name="changesrevision">46f69d22bbc376cefdd92061cd64eaa7e6aaa2a7</param></service></servicedata>
 (No newline at EOF)
 

++++++ typioca-2.11.2.tar.gz -> typioca-3.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/README.md new/typioca-3.0.0/README.md
--- old/typioca-2.11.2/README.md        2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/README.md 2024-07-17 19:59:26.000000000 +0200
@@ -48,6 +48,12 @@
 nix-shell -p typioca
 ```
 
+### openSUSE Tumbleweed
+
+```
+zypper install typioca
+```
+
 ### Scoop
 
 ```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/cmd/config.go 
new/typioca-3.0.0/cmd/config.go
--- old/typioca-2.11.2/cmd/config.go    2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/cmd/config.go     2024-07-17 19:59:26.000000000 +0200
@@ -3,6 +3,7 @@
 import (
        "encoding/json"
        "fmt"
+       "log"
        "os"
        "path/filepath"
 
@@ -11,7 +12,7 @@
        "github.com/kirsle/configdir"
 )
 
-const currentConfigVersion = 3
+const currentConfigVersion = 4
 
 func ReadConfig() Config {
        var config Config
@@ -53,6 +54,11 @@
                config.WordLists[idx].synced = fileExists(elem.Path)
                config.WordLists[idx].syncOK = true
        }
+
+       for idx, elem := range config.LayoutFiles {
+               config.LayoutFiles[idx].synced = fileExists(elem.Path)
+               config.LayoutFiles[idx].syncOk = true
+       }
 }
 
 func WriteConfig(config Config) {
@@ -157,6 +163,52 @@
        )
 }
 
+func githubLayoutsURI(fileName string) string {
+       return fmt.Sprintf("%s%s",
+               
"https://raw.githubusercontent.com/bloznelis/typioca/master/layouts/";,
+               fileName,
+       )
+}
+
+func retrieveLayout(layout LayoutFile) Layout {
+       if layout.Path == "" {
+               return Layout{
+                       Name: layout.Name,
+               }
+       }
+
+       f, err := os.Open(layout.Path)
+       if err != nil {
+               log.Println(layout.Path)
+               panic(err)
+       }
+
+       var res Layout
+       dec := json.NewDecoder(f)
+       if err := dec.Decode(&res); err != nil {
+               panic(err)
+       }
+
+       return res
+}
+
+func defaultLayoutFile(cachePath string, name string, localName string) 
LayoutFile {
+       if localName == "" {
+               return LayoutFile{
+                       Name: name,
+               }
+       }
+
+       path := filepath.Join(cachePath, "layouts", localName)
+
+       return LayoutFile{
+               Name:      name,
+               Path:      path,
+               RemoteURI: githubLayoutsURI(localName),
+               synced:    fileExists(path),
+       }
+}
+
 func defaultWordList(cachePath string, name string, localName string, enabled 
bool, sentences bool) WordList {
        var subdir string
        var uri string
@@ -181,6 +233,7 @@
 
 func defaultConfig() Config {
        cachePath := getCachePath()
+       defaultLayout := defaultLayoutFile(cachePath, "Qwerty", "")
 
        return Config{
                TestSettingCursors: initTestSettingCursors(),
@@ -225,5 +278,12 @@
                        defaultWordList(cachePath, "Peter Pan words", 
"peter-pan.json", true, false),
                        defaultWordList(cachePath, "Peter Pan sentences", 
"peter-pan.json", true, true),
                },
+               LayoutFiles: []LayoutFile{
+                       defaultLayoutFile("", "Qwerty", ""),
+                       defaultLayoutFile(cachePath, "Dvorak", "dvorak.json"),
+                       defaultLayoutFile(cachePath, "Colemak DH", 
"colemak-dh.json"),
+                       defaultLayoutFile(cachePath, "Gallium", "gallium.json"),
+               },
+               Layout: retrieveLayout(defaultLayout),
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/cmd/model.go 
new/typioca-3.0.0/cmd/model.go
--- old/typioca-2.11.2/cmd/model.go     2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/cmd/model.go      2024-07-17 19:59:26.000000000 +0200
@@ -1,6 +1,7 @@
 package cmd
 
 import (
+       "errors"
        "time"
 
        "github.com/bloznelis/typioca/cmd/words"
@@ -219,6 +220,27 @@
        SentenceCountWordlistCursor int
 }
 
+type LayoutFile struct {
+       Name      string
+       Path      string
+       RemoteURI string
+       synced    bool
+       syncOk    bool
+}
+
+func (layoutFile *LayoutFile) getLayout() (Layout, error) {
+       if !layoutFile.synced {
+               return Layout{}, errors.New("LayoutFile not synced")
+       }
+
+       return retrieveLayout(*layoutFile), nil
+}
+
+type Layout struct {
+       Name     string        `json:"name"`
+       Mappings map[rune]rune `json:"mappings"`
+}
+
 type WordList struct {
        Sentences bool
        Name      string
@@ -250,6 +272,8 @@
        TestSettingCursors TestSettingCursors
        EmbededWordLists   []EmbededWordList
        WordLists          []WordList
+       LayoutFiles        []LayoutFile
+       Layout             Layout
        Version            int
 }
 
@@ -257,8 +281,8 @@
        Words []WordList
 }
 
-func (cfg Config) wordListsCount() int {
-       return len(cfg.WordLists) + len(cfg.EmbededWordLists)
+func (cfg Config) configTotalSelectionsCount() int {
+       return len(cfg.WordLists) + len(cfg.EmbededWordLists) + 
len(cfg.LayoutFiles)
 }
 
 type Toggleable interface {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/cmd/update.go 
new/typioca-3.0.0/cmd/update.go
--- old/typioca-2.11.2/cmd/update.go    2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/cmd/update.go     2024-07-17 19:59:26.000000000 +0200
@@ -1,6 +1,8 @@
 package cmd
 
 import (
+       "os"
+
        "github.com/bloznelis/typioca/cmd/words"
        "github.com/charmbracelet/bubbles/stopwatch"
        "github.com/charmbracelet/bubbles/timer"
@@ -119,7 +121,7 @@
                                                commands = append(commands, 
state.timer.timer.Init())
                                                state.timer.isRunning = true
                                        }
-                                       handleRunes(msg, &state.base)
+                                       handleRunes(msg, &state.base, 
state.mainMenu.config.Layout.Mappings)
                                        m.state = state
                                }
                        }
@@ -179,7 +181,7 @@
                                                commands = append(commands, 
state.stopwatch.stopwatch.Init())
                                                state.stopwatch.isRunning = true
                                        }
-                                       handleRunes(msg, &state.base)
+                                       handleRunes(msg, &state.base, 
state.mainMenu.config.Layout.Mappings)
                                        m.state = state
 
                                }
@@ -256,7 +258,7 @@
                                                commands = append(commands, 
state.stopwatch.stopwatch.Init())
                                                state.stopwatch.isRunning = true
                                        }
-                                       handleRunes(msg, &state.base)
+                                       handleRunes(msg, &state.base, 
state.mainMenu.config.Layout.Mappings)
                                        m.state = state
                                }
                        }
@@ -527,15 +529,35 @@
 }
 
 func (configView ConfigView) handleInput(msg tea.Msg, state State) State {
+
+       embedWordListSectionEnd := len(configView.config.EmbededWordLists)
+       wordListSectionEnd := embedWordListSectionEnd + 
len(configView.config.WordLists)
+       layoutSectionEnd := wordListSectionEnd + 
len(configView.config.LayoutFiles)
+
        switch msg := msg.(type) {
        case tea.KeyMsg:
                switch msg.String() {
                case "e":
-                       embededLength := len(configView.config.EmbededWordLists)
-                       if configView.cursor < embededLength {
+                       switch {
+                       case configView.cursor < embedWordListSectionEnd:
                                
configView.config.EmbededWordLists[configView.cursor].toggleEnabled()
-                       } else {
-                               
configView.config.WordLists[configView.cursor-embededLength].toggleEnabled()
+                       case configView.cursor < wordListSectionEnd:
+                               
configView.config.WordLists[configView.cursor-embedWordListSectionEnd].toggleEnabled()
+                       case configView.cursor < layoutSectionEnd:
+                               selected := 
&configView.config.LayoutFiles[configView.cursor-wordListSectionEnd]
+
+                               if selected.Name == "Qwerty" {
+                                       configView.config.Layout = Layout{Name: 
"Qwerty"}
+                                       break
+                               }
+
+                               if !selected.synced {
+                                       selected.toggleSynced()
+                               }
+
+                               if layout, err := selected.getLayout(); err == 
nil {
+                                       configView.config.Layout = layout
+                               }
                        }
 
                        // We might not have wordlist that config points to
@@ -544,9 +566,14 @@
                        WriteConfig(configView.config)
                        state = configView
                case "s":
-                       embededLength := len(configView.config.EmbededWordLists)
-                       if configView.cursor > embededLength-1 {
-                               
configView.config.WordLists[configView.cursor-embededLength].toggleSynced()
+                       switch {
+                       case configView.cursor < embedWordListSectionEnd:
+                               break
+                       case configView.cursor < wordListSectionEnd:
+                               
configView.config.WordLists[configView.cursor-embedWordListSectionEnd].toggleSynced()
+                       case configView.cursor < layoutSectionEnd:
+                               
configView.config.LayoutFiles[configView.cursor-wordListSectionEnd].toggleSynced()
+
                        }
 
                        // We might not have wordlist that config points to
@@ -558,12 +585,12 @@
                        if configView.cursor > 0 {
                                configView.cursor--
                        } else {
-                               configView.cursor = 
configView.config.wordListsCount() - 1
+                               configView.cursor = 
configView.config.configTotalSelectionsCount() - 1
                        }
 
                        state = configView
                case "down", "j":
-                       if configView.cursor < 
configView.config.wordListsCount()-1 {
+                       if configView.cursor < 
configView.config.configTotalSelectionsCount()-1 {
                                configView.cursor++
                        } else {
                                configView.cursor = 0
@@ -578,6 +605,23 @@
        return state
 }
 
+func (lay1 *LayoutFile) toggleSynced() {
+       var err error
+       if lay1.synced {
+               err = os.Remove(lay1.Path)
+       } else {
+               // TODO: Move this function to a more general location?
+               err = words.DownloadFile(lay1.Path, lay1.RemoteURI)
+       }
+
+       if err != nil {
+               lay1.syncOk = false
+       } else {
+               lay1.synced = !lay1.synced
+               lay1.syncOk = true
+       }
+}
+
 func (wl *WordList) toggleSynced() {
        if !wl.isLocal {
                var err error
@@ -674,23 +718,28 @@
        }
 }
 
-func handleRunes(msg tea.KeyMsg, base *TestBase) {
-       base.inputBuffer = append(base.inputBuffer, msg.Runes...)
-       base.rawInputCnt += len(msg.Runes)
-
-       inputLen := len(base.inputBuffer)
-       inputLenDec := inputLen - 1
+func handleRunes(msg tea.KeyMsg, base *TestBase, remappedInput map[rune]rune) {
+       inputLetter := msg.Runes[len(msg.Runes)-1]
 
+       inputLenDec := len(base.inputBuffer)
        letterToInput := base.wordsToEnter[inputLenDec]
-       inputLetter := base.inputBuffer[inputLenDec]
+
+       if r, ok := remappedInput[inputLetter]; ok {
+               inputLetter = r
+       }
+
+       base.inputBuffer = append(base.inputBuffer, inputLetter)
+       base.rawInputCnt += 1
 
        if letterToInput != inputLetter {
                base.mistakes.mistakesAt[inputLenDec] = true
                base.mistakes.rawMistakesCnt = base.mistakes.rawMistakesCnt + 1
        }
 
-       //Set cursor
-       base.cursor = inputLen
+       lenAfterAppend := len(base.inputBuffer)
+
+       // Set cursor
+       base.cursor = lenAfterAppend
 }
 
 func handleSpace(base *TestBase) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/cmd/view.go 
new/typioca-3.0.0/cmd/view.go
--- old/typioca-2.11.2/cmd/view.go      2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/cmd/view.go       2024-07-17 19:59:26.000000000 +0200
@@ -35,6 +35,30 @@
        return fmt.Sprintf("%s %s%s", cursor, line, cursorClose)
 }
 
+func renderSelectionWindow[T any](
+       maxAmtToShow, cursor, prevSelectionAmt int,
+       cursorWidgetStyle StringStyle,
+       selections []T,
+       lineRenderer func(elem T, isCursorOnLine bool) string,
+) string {
+       internalCursorPos := cursor - prevSelectionAmt
+       total := len(selections)
+       upperInc := int(math.Min(math.Max(float64(maxAmtToShow), 
float64(internalCursorPos)), float64(total-1)))
+       lowerInc := int(math.Max(float64(upperInc-maxAmtToShow), float64(0)))
+       var view string
+
+       cursorWidget := fmt.Sprintf("  [%d-%d:%d]", lowerInc+1, upperInc+1, 
total)
+       view += style(cursorWidget, cursorWidgetStyle)
+       view += "\n"
+
+       selectionsToShow := selections[lowerInc : upperInc+1]
+       for idx, elem := range selectionsToShow {
+               view += lineRenderer(elem, idx+lowerInc+prevSelectionAmt == 
cursor)
+       }
+
+       return view
+}
+
 func (m model) View() string {
        var s string
 
@@ -69,9 +93,15 @@
        case ConfigView:
                absolutePad := longestStringLen(names(state.config.WordLists)) 
+ 2
                var view string
-               header := fmt.Sprintf("%s%*s%s/%s\n\n", "  wordlist", 
absolutePad-11, " ", "synced", "enabled")
+               sectionMaxAmountToShow := m.height / 7
+
+               header := "Config\n\n"
                view += header
 
+               wordlistHeader := fmt.Sprintf("%s%*s%s/%s\n\n", "  wordlist", 
absolutePad-11, " ", "synced", "enabled")
+               view += wordlistHeader
+
+               accumulatedLength := len(state.config.EmbededWordLists)
                for idx, elem := range state.config.EmbededWordLists {
                        var enabled string
                        if elem.Enabled {
@@ -89,56 +119,93 @@
                }
                view += "\n"
 
-               maxAmmountToShow := m.height / 7
-               total := len(state.config.WordLists)
-               curs := state.cursor - len(state.config.EmbededWordLists) + 1
-               lower := floor(curs - maxAmmountToShow)
-               upper := int(math.Min(math.Max(float64(curs), 
float64(maxAmmountToShow)), float64(total)))
-
-               wordListsToShow := state.config.WordLists[lower:upper]
-               cursorWidget := fmt.Sprintf("  [%d-%d:%d]", lower+1, upper, 
total)
-
-               view += style(cursorWidget, m.styles.toEnter)
+               view += renderSelectionWindow(
+                       sectionMaxAmountToShow,
+                       state.cursor,
+                       accumulatedLength,
+                       m.styles.toEnter,
+                       state.config.WordLists,
+                       func(elem WordList, isCursorOnLine bool) string {
+                               var synced string
+                               if elem.synced {
+                                       synced = "x"
+                               } else {
+                                       synced = " "
+                               }
+                               if !elem.isLocal {
+                                       synced = style(synced, m.styles.greener)
+                               } else {
+                                       synced = style(synced, m.styles.toEnter)
+                               }
+
+                               var enabled string
+                               if elem.Enabled {
+                                       enabled = "x"
+                               } else {
+                                       enabled = " "
+                               }
+
+                               if !elem.isLocal {
+                                       enabled = style(enabled, 
m.styles.greener)
+                               } else {
+                                       enabled = style(enabled, 
m.styles.toEnter)
+                               }
+
+                               toPad := absolutePad - len(elem.Name)
+                               line := fmt.Sprintf("%s%*s[%s]  [%s] ", 
style(elem.Name, m.styles.greener), toPad, "", synced, enabled)
+                               if !elem.syncOK {
+                                       line = style(dropAnsiCodes(line), 
m.styles.mistakes)
+                               }
+
+                               lineContents := wrapWithCursor(isCursorOnLine, 
line, m.styles.runningTimer)
+                               lineContents += "\n"
+
+                               return lineContents
+                       },
+               )
                view += "\n"
+               accumulatedLength += len(state.config.WordLists)
 
-               for idx, elem := range wordListsToShow {
-                       var synced string
-                       if elem.synced {
-                               synced = "x"
-                       } else {
-                               synced = " "
-                       }
-                       if !elem.isLocal {
-                               synced = style(synced, m.styles.greener)
-                       } else {
-                               synced = style(synced, m.styles.toEnter)
-                       }
-
-                       var enabled string
-                       if elem.Enabled {
-                               enabled = "x"
-                       } else {
-                               enabled = " "
-                       }
-
-                       if !elem.isLocal {
-                               enabled = style(enabled, m.styles.greener)
-                       } else {
-                               enabled = style(enabled, m.styles.toEnter)
-                       }
-
-                       toPad := absolutePad - len(elem.Name)
-                       line := fmt.Sprintf("%s%*s[%s]  [%s] ", 
style(elem.Name, m.styles.greener), toPad, "", synced, enabled)
-                       if !elem.syncOK {
-                               line = style(dropAnsiCodes(line), 
m.styles.mistakes)
-                       }
-
-                       view += 
wrapWithCursor(int(lower)+idx+len(defaultConfig().EmbededWordLists) == 
state.cursor, line, m.styles.runningTimer)
-                       view += "\n"
-               }
+               view += "\n"
+               layoutListHeader := fmt.Sprintf("%s%*s%s/%s\n\n", "  layouts", 
absolutePad-11, " ", "synced", "enabled")
+               view += layoutListHeader
+               view += renderSelectionWindow(
+                       sectionMaxAmountToShow,
+                       state.cursor,
+                       accumulatedLength,
+                       m.styles.toEnter,
+                       state.config.LayoutFiles,
+                       func(elem LayoutFile, isCursorOnLine bool) string {
+                               var synced string
+                               if elem.synced {
+                                       synced = "x"
+                               } else {
+                                       synced = " "
+                               }
+
+                               var enabled string
+                               if elem.Name == state.config.Layout.Name {
+                                       enabled = "x"
+                               } else {
+                                       enabled = " "
+                               }
+
+                               toPad := absolutePad - len(elem.Name)
+                               line := fmt.Sprintf("%s%*s[%s]  [%s] ", 
style(elem.Name, m.styles.greener), toPad, "", synced, enabled)
+
+                               if elem.Name == "Qwerty" {
+                                       line = fmt.Sprintf("%s%*s     [%s] ", 
style(elem.Name, m.styles.greener), toPad, "", enabled)
+                               }
+
+                               lineContent := wrapWithCursor(isCursorOnLine, 
line, m.styles.runningTimer)
+                               lineContent += "\n"
+                               return lineContent
+                       },
+               )
+               view += "\n"
+               accumulatedLength += len(state.config.LayoutFiles)
 
                help := style("s sync/delete, e enable/disable, ctrl+q to 
menu", m.styles.toEnter)
-               cursorWidget = 
lipgloss.NewStyle().Align(lipgloss.Left).Render(cursorWidget)
                help = 
lipgloss.NewStyle().Align(lipgloss.Center).Padding(1).Render(help)
                view = lipgloss.NewStyle().Align(lipgloss.Left).Render(view)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/go.mod new/typioca-3.0.0/go.mod
--- old/typioca-2.11.2/go.mod   2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/go.mod    2024-07-17 19:59:26.000000000 +0200
@@ -3,42 +3,47 @@
 go 1.22.1
 
 require (
-       github.com/BurntSushi/toml v1.3.2
+       github.com/BurntSushi/toml v1.4.0
        github.com/charmbracelet/bubbles v0.18.0
-       github.com/charmbracelet/bubbletea v0.25.0
-       github.com/charmbracelet/lipgloss v0.10.0
-       github.com/charmbracelet/ssh v0.0.0-20240202115812-f4ab1009799a
-       github.com/charmbracelet/wish v1.3.2
+       github.com/charmbracelet/bubbletea v0.26.6
+       github.com/charmbracelet/lipgloss v0.11.0
+       github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917
+       github.com/charmbracelet/wish v1.4.0
        github.com/guptarohit/asciigraph v0.7.1
        github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f
        github.com/muesli/reflow v0.3.0
        github.com/muesli/termenv v0.15.2
        github.com/spf13/cobra v1.8.0
-       golang.org/x/term v0.18.0
+       golang.org/x/term v0.22.0
 )
 
 require (
        github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // 
indirect
        github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
        github.com/charmbracelet/keygen v0.5.0 // indirect
-       github.com/charmbracelet/log v0.3.1 // indirect
+       github.com/charmbracelet/log v0.4.0 // indirect
+       github.com/charmbracelet/x/ansi v0.1.2 // indirect
        github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 // 
indirect
-       github.com/charmbracelet/x/exp/term v0.0.0-20240202113029-6ff29cf0473e 
// indirect
-       github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // 
indirect
+       github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd 
// indirect
+       github.com/charmbracelet/x/input v0.1.0 // indirect
+       github.com/charmbracelet/x/term v0.1.1 // indirect
+       github.com/charmbracelet/x/windows v0.1.0 // indirect
        github.com/creack/pty v1.1.21 // indirect
+       github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // 
indirect
        github.com/go-logfmt/logfmt v0.6.0 // indirect
        github.com/inconshreveable/mousetrap v1.1.0 // indirect
        github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
-       github.com/mattn/go-isatty v0.0.18 // indirect
+       github.com/mattn/go-isatty v0.0.20 // indirect
        github.com/mattn/go-localereader v0.0.1 // indirect
        github.com/mattn/go-runewidth v0.0.15 // indirect
-       github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
+       github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
        github.com/muesli/cancelreader v0.2.2 // indirect
        github.com/rivo/uniseg v0.4.7 // indirect
        github.com/spf13/pflag v1.0.5 // indirect
+       github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
        golang.org/x/crypto v0.21.0 // indirect
        golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
-       golang.org/x/sync v0.6.0 // indirect
-       golang.org/x/sys v0.18.0 // indirect
+       golang.org/x/sync v0.7.0 // indirect
+       golang.org/x/sys v0.22.0 // indirect
        golang.org/x/text v0.14.0 // indirect
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/go.sum new/typioca-3.0.0/go.sum
--- old/typioca-2.11.2/go.sum   2024-04-03 18:08:48.000000000 +0200
+++ new/typioca-3.0.0/go.sum    2024-07-17 19:59:26.000000000 +0200
@@ -1,33 +1,42 @@
-github.com/BurntSushi/toml v1.3.2 
h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/toml v1.3.2/go.mod 
h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.4.0 
h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
+github.com/BurntSushi/toml v1.4.0/go.mod 
h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be 
h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod 
h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1 
h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod 
h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
 github.com/charmbracelet/bubbles v0.18.0 
h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
 github.com/charmbracelet/bubbles v0.18.0/go.mod 
h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
-github.com/charmbracelet/bubbletea v0.25.0 
h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
-github.com/charmbracelet/bubbletea v0.25.0/go.mod 
h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
+github.com/charmbracelet/bubbletea v0.26.6 
h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
+github.com/charmbracelet/bubbletea v0.26.6/go.mod 
h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
 github.com/charmbracelet/keygen v0.5.0 
h1:XY0fsoYiCSM9axkrU+2ziE6u6YjJulo/b9Dghnw6MZc=
 github.com/charmbracelet/keygen v0.5.0/go.mod 
h1:DfvCgLHxZ9rJxdK0DGw3C/LkV4SgdGbnliHcObV3L+8=
-github.com/charmbracelet/lipgloss v0.10.0 
h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
-github.com/charmbracelet/lipgloss v0.10.0/go.mod 
h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
-github.com/charmbracelet/log v0.3.1 
h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
-github.com/charmbracelet/log v0.3.1/go.mod 
h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
-github.com/charmbracelet/ssh v0.0.0-20240202115812-f4ab1009799a 
h1:ryXQeBfu7DN77RFiKLa/VA9VRkMsinpkv4qYparR//k=
-github.com/charmbracelet/ssh v0.0.0-20240202115812-f4ab1009799a/go.mod 
h1:GPT/bjXsVDf5TKq2P1n4zl79ZnGwt2lWr19DomWm7zw=
-github.com/charmbracelet/wish v1.3.2 
h1:9+32OZnfebIw59Mcx0Yhsj6uke727bJVGJb6WolxsxQ=
-github.com/charmbracelet/wish v1.3.2/go.mod 
h1:aulqcv2nEoW14yC3tlkrmIbVN7qDjeH+pzIO239VGTA=
+github.com/charmbracelet/lipgloss v0.11.0 
h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g=
+github.com/charmbracelet/lipgloss v0.11.0/go.mod 
h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8=
+github.com/charmbracelet/log v0.4.0 
h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
+github.com/charmbracelet/log v0.4.0/go.mod 
h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
+github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917 
h1:NZKjJ7d/pzk/AfcJYEzmF8M48JlIrrY00RR5JdDc3io=
+github.com/charmbracelet/ssh v0.0.0-20240401141849-854cddfa2917/go.mod 
h1:8/Ve8iGRRIGFM1kepYfRF2pEOF5Y3TEZYoJaA54228U=
+github.com/charmbracelet/wish v1.4.0 
h1:pL1uVP/YuYgJheHEj98teZ/n6pMYnmlZq/fcHvomrfc=
+github.com/charmbracelet/wish v1.4.0/go.mod 
h1:ew4/MjJVfW/akEO9KmrQHQv1F7bQRGscRMrA+KtovTk=
+github.com/charmbracelet/x/ansi v0.1.2 
h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY=
+github.com/charmbracelet/x/ansi v0.1.2/go.mod 
h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
 github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 
h1:3RXpZWGWTOeVXCTv0Dnzxdv/MhNUkBfEcbaTY0zrTQI=
 github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651/go.mod 
h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
-github.com/charmbracelet/x/exp/term v0.0.0-20240202113029-6ff29cf0473e 
h1:45T85zTqW/gN3FK5/JFM5Jk+LJkdP2gAfJcg8xE5lBs=
-github.com/charmbracelet/x/exp/term v0.0.0-20240202113029-6ff29cf0473e/go.mod 
h1:8NVO/XlUZbcJU5g0gVE7K1YiNnRFqYA3nZzGS/0lBRk=
-github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 
h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
-github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod 
h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
+github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd 
h1:HqBjkSFXXfW4IgX3TMKipWoPEN08T3Pi4SA/3DLss/U=
+github.com/charmbracelet/x/exp/term v0.0.0-20240328150354-ab9afc214dfd/go.mod 
h1:6GZ13FjIP6eOCqWU4lqgveGnYxQo9c3qBzHPeFu4HBE=
+github.com/charmbracelet/x/input v0.1.0 
h1:TEsGSfZYQyOtp+STIjyBq6tpRaorH0qpwZUj8DavAhQ=
+github.com/charmbracelet/x/input v0.1.0/go.mod 
h1:ZZwaBxPF7IG8gWWzPUVqHEtWhc1+HXJPNuerJGRGZ28=
+github.com/charmbracelet/x/term v0.1.1 
h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
+github.com/charmbracelet/x/term v0.1.1/go.mod 
h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
+github.com/charmbracelet/x/windows v0.1.0 
h1:gTaxdvzDM5oMa/I2ZNF7wN78X/atWemG9Wph7Ika2k4=
+github.com/charmbracelet/x/windows v0.1.0/go.mod 
h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
 github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod 
h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
 github.com/creack/pty v1.1.21/go.mod 
h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f 
h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod 
h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
 github.com/go-logfmt/logfmt v0.6.0 
h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
 github.com/go-logfmt/logfmt v0.6.0/go.mod 
h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/guptarohit/asciigraph v0.7.1 
h1:K+JWbRc04XEfv8BSZgNuvhCmpbvX4+9NYd/UxXVnAuk=
@@ -38,15 +47,15 @@
 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod 
h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
 github.com/lucasb-eyer/go-colorful v1.2.0 
h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod 
h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
-github.com/mattn/go-isatty v0.0.18 
h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
-github.com/mattn/go-isatty v0.0.18/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-isatty v0.0.20 
h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod 
h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-localereader v0.0.1 
h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
 github.com/mattn/go-localereader v0.0.1/go.mod 
h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
 github.com/mattn/go-runewidth v0.0.12/go.mod 
h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
 github.com/mattn/go-runewidth v0.0.15 
h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
 github.com/mattn/go-runewidth v0.0.15/go.mod 
h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b 
h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
-github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod 
h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 
h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod 
h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
 github.com/muesli/cancelreader v0.2.2 
h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
 github.com/muesli/cancelreader v0.2.2/go.mod 
h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
 github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
@@ -54,6 +63,7 @@
 github.com/muesli/termenv v0.15.2 
h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
 github.com/muesli/termenv v0.15.2/go.mod 
h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
 github.com/pmezard/go-difflib v1.0.0 
h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod 
h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rivo/uniseg v0.1.0/go.mod 
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.2.0/go.mod 
h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -63,19 +73,22 @@
 github.com/spf13/cobra v1.8.0/go.mod 
h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod 
h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stretchr/testify v1.8.4 
h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.9.0 
h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod 
h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e 
h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod 
h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
 golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
 golang.org/x/crypto v0.21.0/go.mod 
h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/exp v0.0.0-20231006140011-7918f672742d 
h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
 golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod 
h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod 
h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod 
h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
+golang.org/x/term v0.22.0/go.mod 
h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod 
h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/layouts/colemak-dh.json 
new/typioca-3.0.0/layouts/colemak-dh.json
--- old/typioca-2.11.2/layouts/colemak-dh.json  1970-01-01 01:00:00.000000000 
+0100
+++ new/typioca-3.0.0/layouts/colemak-dh.json   2024-07-17 19:59:26.000000000 
+0200
@@ -0,0 +1 @@
+{"name":"Colemak 
DH","mappings":{"100":115,"101":102,"102":116,"104":109,"105":117,"106":110,"107":101,"108":105,"109":104,"110":107,"111":121,"114":112,"115":114,"116":98,"117":108,"118":100,"121":106,"59":111,"98":118}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/layouts/dvorak.json 
new/typioca-3.0.0/layouts/dvorak.json
--- old/typioca-2.11.2/layouts/dvorak.json      1970-01-01 01:00:00.000000000 
+0100
+++ new/typioca-3.0.0/layouts/dvorak.json       2024-07-17 19:59:26.000000000 
+0200
@@ -0,0 +1 @@
+{"Name":"Dvorak","Mappings":{"100":101,"101":46,"102":117,"103":105,"104":100,"105":99,"106":104,"107":116,"108":110,"109":109,"110":98,"111":114,"112":108,"113":39,"114":112,"115":111,"116":121,"117":103,"118":107,"119":44,"120":113,"121":102,"122":59,"39":45,"44":119,"46":118,"47":122,"59":115,"91":47,"93":61,"97":97,"98":120,"99":106}}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/typioca-2.11.2/layouts/gallium.json 
new/typioca-3.0.0/layouts/gallium.json
--- old/typioca-2.11.2/layouts/gallium.json     1970-01-01 01:00:00.000000000 
+0100
+++ new/typioca-3.0.0/layouts/gallium.json      2024-07-17 19:59:26.000000000 
+0200
@@ -0,0 +1 @@
+{"name":"Gallium","mappings":{"100":116,"101":100,"102":115,"104":112,"105":111,"106":104,"107":97,"108":101,"109":102,"110":107,"111":117,"112":44,"113":98,"114":99,"115":114,"116":118,"117":121,"118":122,"119":108,"120":109,"121":106,"122":113,"59":105,"97":110,"98":120,"99":119}}

++++++ vendor.tar.gz ++++++
++++ 36938 lines of diff (skipped)

Reply via email to