Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vim mode experimental #246

Open
wants to merge 42 commits into
base: vim-mode-experimental
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
bdd0df1
Added new vimium.js with code taken from vimium
tobimensch Oct 7, 2018
ced1379
Created overlayVimMode function for displaying vim navigation state
tobimensch Oct 7, 2018
6bd4c96
gofmt code
tobimensch Oct 7, 2018
a78d98b
added command for links hints
tobimensch Oct 7, 2018
8b35a68
Set default DISPLAY environment variable for xclipboard functionality
tobimensch Oct 7, 2018
3c8afed
ignore manifest.json backup file
tobimensch Oct 7, 2018
a04bdac
ignore debug log in interfacer/ directory
tobimensch Oct 18, 2018
0d2dfee
Fixed typo in comment
tobimensch Oct 24, 2018
9329c9f
Added sessions permission
tobimensch Oct 29, 2018
c40c724
Added initial configuration for vim like keybindings.
tobimensch Oct 29, 2018
f730983
Added duplicate_tab, restore_tab commands.
tobimensch Oct 29, 2018
b78d896
Refactored code using switchToTab and added new features.
tobimensch Oct 29, 2018
052aecd
Added features needed for vim like navigation to the webextension.
tobimensch Oct 29, 2018
4099f51
Added vim like navigation. This is still in an early stage.
tobimensch Oct 29, 2018
721b2c8
Instead of adding 1 to Y coord, add 1 to height. This fixes an issues
tobimensch Oct 29, 2018
d037732
Merge branch 'master' of https://github.com/browsh-org/browsh into vi…
tobimensch Oct 29, 2018
61cd7e1
Prettified js files
tobimensch Oct 29, 2018
ae1df35
Fixed typo
tobimensch Oct 29, 2018
034d9c4
Update Go `dep` to v0.5.0
tombh Nov 6, 2018
11f746b
Newer NVM formats package.lock differently
tombh Nov 6, 2018
d17cb59
Update FF Marionette commands
tombh Nov 6, 2018
bf44f91
Update JS and Go deps. Bump Browsh to v1.5.0
tombh Nov 6, 2018
0bda8f1
Adds Golang clipboard dep
tombh Nov 9, 2018
6f998be
Refactors Vim code from tty.go into its own file
tombh Nov 9, 2018
e3568cd
Adds some Vim-specific integration tests
tombh Nov 9, 2018
3beeb76
Fixes tests for Vim mode
tombh Nov 11, 2018
26e9c61
Vim mode: convert unexported symbols to lowercase
tombh Nov 11, 2018
af487ae
Vim mode: Small updates from PR review
tombh Nov 12, 2018
15f541c
Travis CI: Bash timeout for integration tests
tombh Nov 13, 2018
565e6f4
Fixed bug where keyEvents variable was initialized wrongly. This led …
tobimensch Nov 13, 2018
9c668e8
Travis: upload logs to text host
tombh Nov 14, 2018
748bf9d
Gofmt: some minor capitalisation
tombh Nov 14, 2018
6882327
Allow for using Escape to leave input boxes
tobimensch Nov 15, 2018
fbb1cfc
Travis: upload logs to text host
tombh Nov 14, 2018
2bf920b
Gofmt: some minor capitalisation
tombh Nov 14, 2018
d034497
Merge branch 'vim-mode-experimental' of https://github.com/browsh-org…
tobimensch Nov 15, 2018
e10510f
Added vim feature for editing URL in new tab
tobimensch Nov 15, 2018
3449ec1
Fixed bug in key event handling between vim modes, where the same key…
tobimensch Nov 23, 2018
0c0b907
Merge branch 'vim-mode-experimental' of https://github.com/browsh-org…
tobimensch Nov 23, 2018
f04af53
Add a new test HTML page.
j-rewerts Dec 20, 2018
b405afe
Reorganized Vim links tests.
j-rewerts Dec 20, 2018
e084edb
Added lengthy hint building.
j-rewerts Dec 20, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ interfacer/vendor
interfacer/dist
interfacer/interfacer
interfacer/browsh
interfacer/debug
webextension.go
webext/node_modules
webext/dist/*
webext/manifest.json~
dist
*.xpi
8 changes: 4 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ install:
script:
- cd $REPO_ROOT/webext && npm test
- cd $REPO_ROOT/interfacer && go test $(find src/browsh -name *.go | grep -v windows)
- cd $REPO_ROOT/interfacer && go test test/tty/*.go -v -ginkgo.flakeAttempts=3
- cd $REPO_ROOT/interfacer && go test test/http-server/*.go -v
- cd $REPO_ROOT/interfacer && timeout 9m go test test/tty/*.go -v -ginkgo.flakeAttempts=3
- cd $REPO_ROOT/interfacer && timeout 9m go test test/http-server/*.go -v
after_failure:
- cat $REPO_ROOT/interfacer/test/tty/debug.log
- cat $REPO_ROOT/interfacer/test/http-server/debug.log
- cat $REPO_ROOT/interfacer/test/tty/debug.log | curl -F 'f:1=<-' ix.io
- cat $REPO_ROOT/interfacer/test/http-server/debug.log | curl -F 'f:1=<-' ix.io
after_success:
- $REPO_ROOT/contrib/release_if_new_version.sh

15 changes: 12 additions & 3 deletions interfacer/Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions interfacer/Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
name = "github.com/NYTimes/gziphandler"
version = "1.0.1"

[[constraint]]
name = "github.com/atotto/clipboard"
version = "0.1.1"

[[constraint]]
name = "github.com/gdamore/tcell"
version = "1.1.0"
Expand Down
7 changes: 7 additions & 0 deletions interfacer/src/browsh/browsh.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ func TTYStart(injectedScreen tcell.Screen) {
Log("Starting Browsh CLI client")
go readStdin()
startWebSocketServer()
setupLinkHints()
}

func toInt(char string) int {
Expand All @@ -181,6 +182,12 @@ func ttyEntry() {
// from tcell.
os.Setenv("TERM", "xterm-truecolor")
}
// This is for getting the clipboard (github.com/atotto/clipboard) to work
// with the applications xsel and xclip on systems with an X display server.
if os.Getenv("DISPLAY") == "" {
os.Setenv("DISPLAY", ":0")
}

realScreen, err := tcell.NewScreen()
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
Expand Down
2 changes: 2 additions & 0 deletions interfacer/src/browsh/comms.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func handleWebextensionCommand(message []byte) {
}
case "/screenshot":
saveScreenshot(parts[1])
case "/link_hints":
parseJSONLinkHints(strings.Join(parts[1:], ","))
default:
Log("WEBEXT: " + string(message))
}
Expand Down
60 changes: 60 additions & 0 deletions interfacer/src/browsh/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,66 @@ func getFirefoxProfilePath() string {
func setDefaults() {
// Temporary experimental configurable keybindings
viper.SetDefault("tty.keys.next-tab", []string{"\u001c", "28", "2"})

// Vim commands
vimKeyMap["normal gg"] = "scrollToTop"
vimKeyMap["normal G"] = "scrollToBottom"
vimKeyMap["normal j"] = "scrollDown"
vimKeyMap["normal k"] = "scrollUp"
vimKeyMap["normal h"] = "scrollLeft"
vimKeyMap["normal l"] = "scrollRight"
vimKeyMap["normal d"] = "scrollHalfPageDown"
vimKeyMap["normal <C-d>"] = "scrollHalfPageDown"
vimKeyMap["normal u"] = "scrollHalfPageUp"
vimKeyMap["normal <C-u>"] = "scrollHalfPageUp"
vimKeyMap["normal e"] = "editURL"
vimKeyMap["normal ge"] = "editURL"
vimKeyMap["normal gE"] = "editURLInNewTab"
vimKeyMap["normal H"] = "historyBack"
vimKeyMap["normal L"] = "historyForward"
vimKeyMap["normal J"] = "prevTab"
vimKeyMap["normal K"] = "nextTab"
vimKeyMap["normal r"] = "reload"
vimKeyMap["normal xx"] = "removeTab"
vimKeyMap["normal X"] = "restoreTab"
vimKeyMap["normal t"] = "newTab"
vimKeyMap["normal T"] = "searchForTab"
vimKeyMap["normal /"] = "findMode"
vimKeyMap["normal n"] = "findNext"
vimKeyMap["normal N"] = "findPrevious"
vimKeyMap["normal g0"] = "firstTab"
vimKeyMap["normal g$"] = "lastTab"
vimKeyMap["normal gu"] = "urlUp"
vimKeyMap["normal gU"] = "urlRoot"
vimKeyMap["normal <<"] = "moveTabLeft"
vimKeyMap["normal >>"] = "moveTabRight"
vimKeyMap["normal ^"] = "previouslyVisitedTab"
vimKeyMap["normal m"] = "makeMark"
vimKeyMap["normal '"] = "gotoMark"
vimKeyMap["normal i"] = "insertMode"
vimKeyMap["normal I"] = "insertModeHard"
vimKeyMap["normal yy"] = "copyURL"
vimKeyMap["normal p"] = "openClipboardURL"
vimKeyMap["normal P"] = "openClipboardURLInNewTab"
vimKeyMap["normal gi"] = "focusFirstTextInput"
vimKeyMap["normal f"] = "openLinkInCurrentTab"
vimKeyMap["normal F"] = "openLinkInNewTab"
vimKeyMap["normal <M-f>"] = "openMultipleLinksInNewTab"
vimKeyMap["normal yf"] = "copyLinkURL"
vimKeyMap["normal [["] = "followLinkLabeledPrevious"
vimKeyMap["normal ]]"] = "followLinkLabeledNext"
vimKeyMap["normal yt"] = "duplicateTab"
vimKeyMap["normal v"] = "visualMode"
vimKeyMap["normal ?"] = "viewHelp"
vimKeyMap["caret v"] = "visualMode"
vimKeyMap["caret h"] = "moveCaretLeft"
vimKeyMap["caret l"] = "moveCaretRight"
vimKeyMap["caret j"] = "moveCaretDown"
vimKeyMap["caret k"] = "moveCaretUp"
vimKeyMap["caret <Enter>"] = "clickAtCaretPosition"
vimKeyMap["visual c"] = "caretMode"
vimKeyMap["visual o"] = "swapVisualModeCursorPosition"
vimKeyMap["visual y"] = "copyVisualModeSelection"
}

func loadConfig() {
Expand Down
6 changes: 3 additions & 3 deletions interfacer/src/browsh/frame_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ func (f *frame) updateInputBoxes(incoming incomingFrameText) {
inputBox := f.inputBoxes[incomingInputBox.ID]
inputBox.X = incomingInputBox.X
// TODO: Why do we have to add the 1 to the y coord??
inputBox.Y = (incomingInputBox.Y + 1) / 2
inputBox.Y = (incomingInputBox.Y + 0) / 2
inputBox.Width = incomingInputBox.Width
inputBox.Height = incomingInputBox.Height / 2
inputBox.Height = (incomingInputBox.Height / 2) + 1
inputBox.FgColour = incomingInputBox.FgColour
inputBox.TagName = incomingInputBox.TagName
inputBox.Type = incomingInputBox.Type
Expand Down Expand Up @@ -312,7 +312,7 @@ func (f *frame) maybeFocusInputBox(x, y int) {
left := inputBox.X
right := inputBox.X + inputBox.Width
if x >= left && x < right && y >= top && y < bottom {
urlBarFocus(false)
URLBarFocus(false)
inputBox.isActive = true
activeInputBox = inputBox
}
Expand Down
7 changes: 5 additions & 2 deletions interfacer/src/browsh/input_box.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var activeInputBox *inputBox
// A box into which you can enter text. Generally will be forwarded to a standard
// HTML input box in the real browser.
//
// Note that tcell alreay has some ready-made code in its 'views' concept for
// Note that tcell already has some ready-made code in its 'views' concept for
// dealing with input areas. However, at the time of writing it wasn't well documented,
// so it was unclear how easy it would be to integrate the requirements of Browsh's
// input boxes - namely overlaying them onto the existing graphics and having them
Expand Down Expand Up @@ -181,7 +181,7 @@ func (i *inputBox) handleEnterKey(modifier tcell.ModMask) {
} else {
sendMessageToWebExtension("/url_bar," + string(i.text))
}
urlBarFocus(false)
URLBarFocus(false)
}
if i.isMultiLine() && modifier != tcell.ModAlt {
i.cursorInsertRune([]rune("\n")[0])
Expand Down Expand Up @@ -237,6 +237,9 @@ func handleInputBoxInput(ev *tcell.EventKey) {
case tcell.KeyEnter:
activeInputBox.removeSelectedText()
activeInputBox.handleEnterKey(ev.Modifiers())
case tcell.KeyEscape:
activeInputBox.isActive = false
activeInputBox = nil
case tcell.KeyRune:
activeInputBox.removeSelectedText()
activeInputBox.cursorInsertRune(ev.Rune())
Expand Down
85 changes: 79 additions & 6 deletions interfacer/src/browsh/tab.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ var tabsOrder []int
// the tab being deleted, so we need to keep track of all deleted IDs
var tabsDeleted []int

// ID of the tab that was active before the current one
var previouslyVisitedTabID int

// A single tab synced from the browser
type tab struct {
ID int `json:"id"`
Expand Down Expand Up @@ -54,6 +57,10 @@ func newTab(id int) {
}
}

func restoreTab() {
sendMessageToWebExtension("/restore_tab")
}

func removeTab(id int) {
if len(Tabs) == 1 {
quitBrowsh()
Expand All @@ -77,23 +84,63 @@ func removeTabIDfromTabsOrder(id int) {
}
}

func moveTabLeft(id int) {
// If the tab ID is already completely to the left in the tab order
// there's nothing to do
if tabsOrder[0] == id {
return
}

for i, tabID := range tabsOrder {
if tabID == id {
tabsOrder[i-1], tabsOrder[i] = tabsOrder[i], tabsOrder[i-1]
break
}
}
}

func moveTabRight(id int) {
// If the tab ID is already completely to the right in the tab order
// there's nothing to do
if tabsOrder[len(tabsOrder)-1] == id {
return
}

for i, tabID := range tabsOrder {
if tabID == id {
tabsOrder[i+1], tabsOrder[i] = tabsOrder[i], tabsOrder[i+1]
break
}
}
}

func duplicateTab(id int) {
sendMessageToWebExtension(fmt.Sprintf("/duplicate_tab,%d", id))
}

// Creating a new tab in the browser without a URI means it won't register with the
// web extension, which means that, come the moment when we actually have a URI for the new
// tab then we can't talk to it to tell it navigate. So we need to only create a real new
// tab when we actually have a URL.
func createNewEmptyTab() {
createNewEmptyTabWithURI("")
}

func createNewEmptyTabWithURI(URI string) {
if isNewEmptyTabActive() {
return
}
newTab(-1)
tab := Tabs[-1]
tab.Title = "New Tab"
tab.URI = ""
tab.URI = URI
tab.Active = true
CurrentTab = tab
CurrentTab.frame.resetCells()
renderUI()
urlBarFocus(true)
URLBarFocus(true)
// Allows for typing directly at the end of URI
urlInputBox.selectionOff()
renderCurrentTabWindow()
}

Expand All @@ -109,15 +156,41 @@ func nextTab() {
} else {
i++
}
sendMessageToWebExtension(fmt.Sprintf("/switch_to_tab,%d", tabsOrder[i]))
CurrentTab = Tabs[tabsOrder[i]]
renderUI()
renderCurrentTabWindow()
switchToTab(tabsOrder[i])
break
}
}
}

func prevTab() {
for i := 0; i < len(tabsOrder); i++ {
if tabsOrder[i] == CurrentTab.ID {
if i-1 < 0 {
i = len(tabsOrder) - 1
} else {
i--
}
switchToTab(tabsOrder[i])
break
}
}
}

func previouslyVisitedTab() {
if previouslyVisitedTabID == 0 {
return
}
switchToTab(previouslyVisitedTabID)
}

func switchToTab(num int) {
sendMessageToWebExtension(fmt.Sprintf("/switch_to_tab,%d", num))
previouslyVisitedTabID = CurrentTab.ID
CurrentTab = Tabs[num]
renderUI()
renderCurrentTabWindow()
}

func isTabPreviouslyDeleted(id int) bool {
for i := 0; i < len(tabsDeleted); i++ {
if tabsDeleted[i] == id {
Expand Down
Loading