summary refs log blame commit diff stats
path: root/widgets/account.go
blob: ecccd1b05cee746462a8c250f1663c3f09a82157 (plain) (tree)
24daef8 `~/.config/ranger/commands_full.py`.
* Fixed broken copying of symlinks

# 2013-05-24: Version 1.6.1
* Added support for version control systems, see:
  http://lists.nongnu.org/archive/html/ranger-users/2013-03/msg00007.html
* Added :scout command as a unified backend to :find, :search, etc
* Added `open_all_images` setting to remove the need for external scripts
  to handle opening of all images in a directory at once.
* Now previewing with `i` uses the whole available width.

# 2013-02-22: Version 1.6.0
* Overhauled all config files.  Please update them or use the --clean switch
* Added `examples/` directory to source code which contains sample programs or
  plugins that can be used together with ranger
* Added progress bars to copying, moving and directory loading processes
* Added feature to draw images inside the console using w3mimgdisplay (you need
  to add `set preview_images true` in rc.conf)
* Added a plugin system like in the program `anki`, i.e. place any python file
  into ~/.config/ranger/plugins/ and it will be imported by ranger
* Added a separate file launcher named `rifle` that is configured through
  rifle.conf and is installed as a standalone program.
  Using `ranger [filename]` from the shell for opening files is deprecated now,
  please use `rifle [filename]` instead.
* Added `uq` keybinding to undo closed tabs
* Added :setlocal command to change settings for specific directories only
* Added :travel command to move more quickly to your destination
* Added 256 color support for scope.sh
* Added a real yes/no prompt for :delete command
* Added settings: `confirm_on_delete`, `draw_progress_bar_in_status_bar`,
  `preview_images`, `status_bar_on_top`, `update_tmux_title`
* Added commands: `:mark_tag`, `:unmark_tag`
* Added BSD-friendly setsid implementation
* Added as-you-type filtering for `:filter` command
* Replaced `options.py` file by :set commands in rc.conf
* Replaced `apps.py` file with rifle.conf
* Improved `r` key to interface with rifle
* Rewritten `scope.sh` in POSIX shell
* Changed copying/moving code to work without GNU coreutils
* Changed key to untag files from `T` to `ut`
* Changed the flag `d` (for detached) to `f` (for fork) in program launcher
* Changed appearance of keybinding-hints and bookmarks
* Changed tabs with 4 spaces in the source code (see PEP 8)
* Removed ranger.core.environment class
* Removed settings: `colorscheme_overlay`, `draw_bookmark_borders`,
  `init_function`, `load_default_rc`
* Fixed zombie process apocalypse
* Fixed `draw_borders=true` in combination with `padding_right=false`

# 2012-08-10: Version 1.5.5
* Ensure that detached programs continue to run when ranger is killed

# 2012-05-03: Version 1.5.4
* Added exiftool to scope.sh by default
* Fixed a crash when entering a directory with a unicode name
* Speedup in `ranger.ext.get_executables`

# 2012-03-05: Version 1.5.3
* Added --selectfile option that selects a certain file on startup
* Added --list-tagged-files option
* Added --cmd option to run commands on startup
* Added --profile option for additional debug information on exit
* Added a visual mode (activate with `V`, deactivate with Esc)
* Added a reversed visual mode (activate with `uV`)
* Added `$RANGER_LEVEL` environment variable which ranger sets to `1` or higher
  so programs can know that they were spawned from ranger
* Added run flag `r` for running with root privileges (needs sudo)
* Added run flag `t` for running in a new terminal (as specified in $TERMCMD)
* Added :relink command to change destinations of symlinks
* Added `dc` binding for getting the cumulative size of a directory
* Added `autoupdate_cumulative_size` option
* Added `pht` binding to Paste Hardlinked subTrees (like cp -l)
* Improved sorting speed of signals (noticeable when caching many directories)
* Improved drawing speed
* Fixed unexpected behavior when displaying nonprintable characters
* Fixed :bulkrename to work with files starting with a minus sign
* Fixed RangerChooser example in man page
* Fixed crash when opening images with sxiv/feh by running `ranger <image>`

# 2011-10-23: Version 1.5.2
* Fixed graphical bug that appears in certain cases when drawing
  characters at the right edge.

# 2011-10-23: Version 1.5.1
* Added `fm.select_file(path)`
* Added --choosefiles option (like --choosefile, but chooses multiple files)
* Fixed --list-unused-keys
* Fixed Zombie processes
* Fixed handling of filenames with undecodable bytes (unicode surrogates)
* Fixed crashes due to incomplete loading of directories
* Fixed tab completion of the command `shell`
* Fixed `ot` and `oT` keys in rc.conf
* Fixed parsing of chained commands (like in the binding `om`)

# 2011-10-11: Version 1.5.0
* Full python3.2 compatibility
* Added new configuration file `rc.conf` which contains a list
  of commands that are executed on startup - mainly used for keybindings
* Added --list-unused-keys
* Added new program handlers to apps.py
* Added pop-up window for keychains and bookmarks
* Added `load_default_rc` option
* Fixed all known unicode issues
* Fixed crash when $TERM is unknown to the system
* Fixed scrolling in colored preview
* Changed the default `column_ratios` to 1/3/4 and sorting method to `natural`
* Changed :rename so it doesn't overwrite existing files
* Internal actions are now accessible as commands
* Replaced unittests by doctests
* Replaced integrated help with an extended man page and dynamic lists
  of keybindings, commands and settings.
* Removed `keys.py` configuration file in favor of `rc.conf`
* Removed `texas` colorscheme
* apps.py: Now able to define programs that only run with Xorg
* commands.py: Using parse(self.line) to parse the line is unnecessary now.
  parse(self.line).rest(n) is now written as self.rest(n).
  However, parse(self.line).chunk(n) has been renamed to self.arg(n).
* commands.py: parse(self.line) + X is now self.firstpart + X
* commands.py: New special attribute `resolve_macros` which decides whether
  strings like %f should be expanded to the name of the current file, etc.
* commands.py: New special attribute `escape_macros_for_shell` to toggle
  whether or not macros should be escaped, so you can use them in other
  commands than :shell, for example :edit %f
* Countless small fixes and improvements

# 2011-10-02: Version 1.4.4
* Added keys for chmod (like +ow for `chmod o+w`, etc)
* Added `c` flag for running files
* Added various key bindings
* Added wavpack and webm types to mime.types
* Added option `display_tags_in_all_columns`
* Added command.cancel method which is called when pressing ESC in console
* Added sorting and cycling by ctime and atime
* Added custom tags (press "x)
* Added bittorrent preview
* Fixed blocking when using interactive scripts in scope.sh
* Fixed issues with ALT key
* Fixed pager crash when trying to read non-readable file
* Forbid piping things into ranger
* Improved hints

# 2011-04-05: Version 1.4.3
* Fixed mimetype checking when invoking ranger with a filename
* Fixed loss of bookmarks when disk is full
* Minor improvements

# 2011-03-05: Version 1.4.2
* Added --choosefile and --choosedir flag
* Added use of bookmarks in tab completion of the :cd command
* Fixed bug with detached programs and python 3.2

# 2011-01-04: Version 1.4.1
* Fixed crash when preview failed under some circumstances
* Fixed graphical bug when pressing i

# 2010-12-22: Version 1.4.0
* Added option to use any external scripts for previews (see scope.sh)
* Added key: zv to toggle the use of the external script
* Added indicator for the used filter (type `zf`)
* Added option `padding_right` to remove whitespace if theres no preview
* Added command `:search_inc` for incremental search
* Added commands `:save_copy_buffer` and `:load_copy_buffer` to share
  the copied files between ranger instances
* Added mimeopen as a fallback if no useful application can be found
* Added natural sort, sorts 1foo before 10foo. (type `on`)
* Added keys: yp, yd and yb to copy path, dirname or basename to seleciton
* Let `open_with` use the selection, not just one file
* Run files with right mouse click
* Implemented copying via coreutils rather than internal python code
* Improved handling of unicode
* Some restructuration of the source code

# 2010-12-13: Version 1.2.3
* Enable binding to alt-keys
* Fixed memory leak in garbage collecting of old, unused directory objects
* Fixed python3 incompatibilities
* Fixed problems with identifying changes of files
* Fixed lazy lookup of some FSObject attributes

# 2010-10-10: Version 1.2.2
* Prevent currently used directories from being garbage collected
* Disable mouse buttons when console is open
* Fixed :cd command: Without arguments, cd's into $HOME
* Fixed bug which prevented pydoc to work on some config files
* Fixed some bugs in `snow` and `jungle` colorschemes
* Several other clean-ups and fixes

# 2010-09-16: Version 1.2.1
* Fixed yy/pp bug when yanking multiple directories

# 2010-09-13: Version 1.2.0
* !!! Changed the default configuration directory to ~/.config/ranger !!!
* Removed `Console Modes`, each old mode is now a simple command
* Disabled file previews by default if ranger is used by root
* Allow to jump to specific help sections by typing two numbers, e.g. 13?
* Added keys: da, dr, ya, yr for adding and removing files from copy buffer
* Added keys: gl and gL to resolve links, see 11?
* Added key: pL to create a relative symlink
* Added %<LETTER> and %<N><LETTER> macros for the console, see 33?
* Fixed ansi codes for colors in the pager
* Use the file ~/.mime.types for mime type detection
* Several clean-ups and fixes

# 2010-07-17: Version 1.1.2
* Fix crash when using scrollwheel to scroll down in some cases
* The command `ranger dir1 dir2 ...` opens multiple directories in tabs
* Removed pydoc html documentation by default, re-create it with `make doc`
* Minor fixes

# 2010-06-18: Version 1.1.1
* New install script, `setup.py`
* New flag for running programs: `w` (waits for enter press)
* Minor fixes

# 2010-06-09: Version 1.1.0
* Added a man page
* Tab support
* Improved directory loading performance
* Commands are definable in ~/.ranger/commands.py
* Case insensitive sorting (type zs)
* Better UTF support
* Possibility to turn off previews (zp and zP)
* Changing options with :set (e.g. `:set column_ratios=1,2,3,4`)
* Ask for confirmation when using :delete
* New invocation flag: --fail-unless-cd
* New hotkeys, commands, options.
* New syntax for ~/.ranger/keys.py
* Several user contributions
* And tons of general improvements
 

                                      




















                                                                               



                    



                                                             
















                                                             

                                               



                                                                 

         




                                                       



                                                  
                                                             



                                                  








                                                                                               

                                                                               

                                                                                      





                                                              
                                                                                    











                                                                  
 
package widgets

import (
	"fmt"
	"log"
	"time"

	"github.com/gdamore/tcell"

	"git.sr.ht/~sircmpwn/aerc2/config"
	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
	"git.sr.ht/~sircmpwn/aerc2/worker"
	"git.sr.ht/~sircmpwn/aerc2/worker/types"
)

type AccountView struct {
	acct         *config.AccountConfig
	conf         *config.AercConfig
	dirlist      *DirectoryList
	grid         *ui.Grid
	logger       *log.Logger
	interactive  ui.Interactive
	onInvalidate func(d ui.Drawable)
	runCmd       func(cmd string) error
	msglist      *MessageList
	msgStores    map[string]*MessageStore
	pendingKeys  []config.KeyStroke
	statusline   *StatusLine
	statusbar    *ui.Stack
	worker       *types.Worker
}

func NewAccountView(conf *config.AercConfig, acct *config.AccountConfig,
	logger *log.Logger, runCmd func(cmd string) error) *AccountView {

	statusbar := ui.NewStack()
	statusline := NewStatusLine()
	statusbar.Push(statusline)

	grid := ui.NewGrid().Rows([]ui.GridSpec{
		{ui.SIZE_WEIGHT, 1},
		{ui.SIZE_EXACT, 1},
	}).Columns([]ui.GridSpec{
		{ui.SIZE_EXACT, conf.Ui.SidebarWidth},
		{ui.SIZE_WEIGHT, 1},
	})
	grid.AddChild(statusbar).At(1, 1)

	worker, err := worker.NewWorker(acct.Source, logger)
	if err != nil {
		statusline.Set(fmt.Sprintf("%s", err))
		return &AccountView{
			acct:       acct,
			grid:       grid,
			logger:     logger,
			statusline: statusline,
		}
	}

	dirlist := NewDirectoryList(acct, logger, worker)
	grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT)).Span(2, 1)

	msglist := NewMessageList(logger)
	grid.AddChild(msglist).At(0, 1)

	view := &AccountView{
		acct:       acct,
		conf:       conf,
		dirlist:    dirlist,
		grid:       grid,
		logger:     logger,
		msglist:    msglist,
		msgStores:  make(map[string]*MessageStore),
		runCmd:     runCmd,
		statusbar:  statusbar,
		statusline: statusline,
		worker:     worker,
	}

	go worker.Backend.Run()
	go func() {
		for {
			msg := <-worker.Messages
			msg = worker.ProcessMessage(msg)
			view.onMessage(msg)
		}
	}()

	worker.PostAction(&types.Configure{Config: acct}, nil)
	worker.PostAction(&types.Connect{}, view.connected)
	statusline.Set("Connecting...")

	return view
}

func (acct *AccountView) Name() string {
	return acct.acct.Name
}

func (acct *AccountView) Children() []ui.Drawable {
	return acct.grid.Children()
}

func (acct *AccountView) OnInvalidate(onInvalidate func(d ui.Drawable)) {
	acct.grid.OnInvalidate(func(_ ui.Drawable) {
		onInvalidate(acct)
	})
}

func (acct *AccountView) Invalidate() {
	acct.grid.Invalidate()
}

func (acct *AccountView) Draw(ctx *ui.Context) {
	acct.grid.Draw(ctx)
}

func (acct *AccountView) beginExCommand() {
	exline := NewExLine(func(command string) {
		err := acct.runCmd(command)
		if err != nil {
			acct.statusline.Push(" "+err.Error(), 10*time.Second).
				Color(tcell.ColorRed, tcell.ColorWhite)
		}
		acct.statusbar.Pop()
		acct.interactive = nil
	}, func() {
		acct.statusbar.Pop()
		acct.interactive = nil
	})
	acct.interactive = exline
	acct.statusbar.Push(exline)
}

func (acct *AccountView) Event(event tcell.Event) bool {
	if acct.interactive != nil {
		return acct.interactive.Event(event)
	}

	switch event := event.(type) {
	case *tcell.EventKey:
		acct.pendingKeys = append(acct.pendingKeys, config.KeyStroke{
			Key:  event.Key(),
			Rune: event.Rune(),
		})
		result, output := acct.conf.Lbinds.GetBinding(acct.pendingKeys)
		switch result {
		case config.BINDING_FOUND:
			acct.pendingKeys = []config.KeyStroke{}
			for _, stroke := range output {
				simulated := tcell.NewEventKey(
					stroke.Key, stroke.Rune, tcell.ModNone)
				acct.Event(simulated)
			}
		case config.BINDING_INCOMPLETE:
			return false
		case config.BINDING_NOT_FOUND:
			acct.pendingKeys = []config.KeyStroke{}
			if event.Rune() == ':' {
				acct.beginExCommand()
				return true
			}
		}
	}
	return false
}

func (acct *AccountView) connected(msg types.WorkerMessage) {
	switch msg := msg.(type) {
	case *types.Done:
		acct.statusline.Set("Listing mailboxes...")
		acct.logger.Println("Listing mailboxes...")
		acct.dirlist.UpdateList(func(dirs []string) {
			var dir string
			for _, _dir := range dirs {
				if _dir == "INBOX" {
					dir = _dir
					break
				}
			}
			if dir == "" {
				dir = dirs[0]
			}
			acct.dirlist.Select(dir)
			acct.logger.Println("Connected.")
			acct.statusline.Set("Connected.")
		})
	case *types.CertificateApprovalRequest:
		// TODO: Ask the user
		acct.worker.PostAction(&types.ApproveCertificate{
			Message:  types.RespondTo(msg),
			Approved: true,
		}, acct.connected)
	}
}

func (acct *AccountView) Directories() *DirectoryList {
	return acct.dirlist
}

func (acct *AccountView) Messages() *MessageList {
	return acct.msglist
}

func (acct *AccountView) onMessage(msg types.WorkerMessage) {
	switch msg := msg.(type) {
	case *types.Done:
		switch msg.InResponseTo().(type) {
		case *types.OpenDirectory:
			if store, ok := acct.msgStores[acct.dirlist.selected]; ok {
				// If we've opened this dir before, we can re-render it from
				// memory while we wait for the update and the UI feels
				// snappier. If not, we'll unset the store and show the spinner
				// while we download the UID list.
				acct.msglist.SetStore(store)
			} else {
				acct.msglist.SetStore(nil)
			}
			acct.worker.PostAction(&types.FetchDirectoryContents{},
				func(msg types.WorkerMessage) {
					store := acct.msgStores[acct.dirlist.selected]
					acct.msglist.SetStore(store)
				})
		}
	case *types.DirectoryInfo:
		if store, ok := acct.msgStores[msg.Name]; ok {
			store.Update(msg)
		} else {
			acct.msgStores[msg.Name] = NewMessageStore(acct.worker, msg)
		}
	case *types.DirectoryContents:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.MessageInfo:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.Error:
		acct.logger.Printf("%v", msg.Error)
		acct.statusline.Set(fmt.Sprintf("%v", msg.Error)).
			Color(tcell.ColorRed, tcell.ColorDefault)
	}
}