aboutsummaryrefslogtreecommitdiff
path: root/window.go
diff options
context:
space:
mode:
Diffstat (limited to 'window.go')
-rw-r--r--window.go357
1 files changed, 0 insertions, 357 deletions
diff --git a/window.go b/window.go
deleted file mode 100644
index 0e85bb7..0000000
--- a/window.go
+++ /dev/null
@@ -1,357 +0,0 @@
-package main
-
-import (
- "crypto/sha256"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
- "time"
-
- "github.com/gdamore/tcell"
- "github.com/pkg/errors"
- "github.com/prodhe/poe/gapbuffer"
-)
-
-// File holds information about the file on disk. It is managed by Window and the bytes on disk are optionally loaded into a Text.
-type File struct {
- name string
- read bool // true if file has been read
- mtime time.Time // of file when last read/written
- sha256 string // of file when last read/written
-}
-
-// Window is a tagline and a body with an optional underlying file on disk. It is the main component and handles all events apart from the system wide shortcuts.
-type Window struct {
- x, y, w, h int
- file *File
- isdir bool
- body *View
- tagline *View
- col *Column // reference to the column where in
- hidden bool
- collapsed bool // not implemented
- qcnt int // quit count
-}
-
-// NewWindow returns a fresh window associated with the given filename. For special case filenames, look at the package constants.
-func NewWindow(fn string) *Window {
- fnabs := fn
- if fn != FnEmptyWin {
- var err error
- fnabs, err = filepath.Abs(fn)
- if err != nil {
- printMsg("%s\n", err)
- fnabs = FnEmptyWin
- }
- }
- win := &Window{
- body: &View{
- text: &Text{buf: gapbuffer.New()},
- what: ViewBody,
- style: bodyStyle,
- cursorStyle: bodyCursorStyle,
- hilightStyle: bodyHilightStyle,
- tabstop: 4,
- focused: true,
- },
- tagline: &View{
- text: &Text{buf: gapbuffer.New()},
- what: ViewTagline,
- style: tagStyle,
- cursorStyle: tagCursorStyle,
- hilightStyle: tagHilightStyle,
- tabstop: 4,
- },
- file: &File{name: fnabs},
- }
-
- fmt.Fprintf(win.tagline, "%s%s Del ",
- win.Flags(),
- win.Name(),
- )
-
- return win
-}
-
-func AllWindows() []*Window {
- var ws []*Window
- for _, col := range workspace.cols {
- ws = append(ws, col.windows...)
- }
- return ws
-}
-
-// FindWindow searches for the given name in current windows and returns a pointer if one already exists. Nil otherwise. Name assumes to be an absolute path.
-func FindWindow(name string) *Window {
- for _, win := range AllWindows() {
- if win.NameAbs() == name {
- return win
- }
- }
- return nil
-}
-
-func (win *Window) LoadBuffer() bool {
- if win.file.read || win.Name() == FnEmptyWin || win.body.what == ViewScratch {
- return false
- }
-
- info, err := os.Stat(win.file.name)
- if err != nil {
- // if the file exists, print why we could not open it
- // otherwise just close silently
- if os.IsExist(err) {
- printMsg("%s\n", err)
- }
- win.Close()
- return false
- }
-
- // name is a directory; list it's content into the buffer
- if info.IsDir() {
- files, err := ioutil.ReadDir(win.file.name)
- if err != nil {
- printMsg("%s\n", err)
- return false
- }
-
- win.body.what = ViewScratch
- win.isdir = true
-
- // list files in dir
- for _, f := range files {
- dirchar := ""
- if f.IsDir() {
- dirchar = string(filepath.Separator)
- }
- fmt.Fprintf(win.body.text.buf, "%s%s\n", f.Name(), dirchar)
- }
- return true
- }
-
- // name is a file
- fh, err := os.OpenFile(win.file.name, os.O_RDWR|os.O_CREATE, 0644)
- if err != nil {
- printMsg("%s\n", err)
- return false
- }
- defer fh.Close()
-
- if _, err := io.Copy(win.body.text.buf, fh); err != nil {
- printMsg("%s\n", err)
- return false
- }
- fh.Seek(0, 0)
-
- h := sha256.New()
- if _, err := io.Copy(h, fh); err != nil {
- printMsg("%s\n", err)
- return false
- }
- win.file.sha256 = fmt.Sprintf("%x", h.Sum(nil))
-
- win.file.mtime = info.ModTime()
- win.file.read = true
-
- win.body.SetCursor(0, io.SeekStart)
-
- return true
-}
-
-// SaveFile replaces disk file with buffer content. Returns error if no disk file is set.
-func (win *Window) SaveFile() (int, error) {
- if win.NameTag() == FnEmptyWin {
- return 0, errors.New("no filename")
- }
-
- if win.Name() == FnMessageWin { // can not save +poe window
- return 0, nil
- }
-
- // TODO: check this in real time in case of tag name change...
- if win.isdir { // can not save a directory
- return 0, nil
- }
-
- // check for file existence if we recently changed the file name
- openmasks := os.O_RDWR | os.O_CREATE
- var namechange bool
- if win.Name() != win.NameTag() { // user has changed name
- openmasks |= os.O_EXCL // must not already exist
- namechange = true // to skip sha256 checksum
- }
-
- f, err := os.OpenFile(win.NameTag(), openmasks, 0644)
- if err != nil {
- if os.IsExist(err) {
- printMsg("%s already exists\n", win.NameTag())
- return 0, nil
- }
- return 0, err
- }
- defer f.Close()
-
- h := sha256.New()
- if _, err := io.Copy(h, f); err != nil {
- return 0, errors.Wrap(err, "sha256")
- }
- hhex := fmt.Sprintf("%x", h.Sum(nil))
-
- // verify checksum if the file is not newly created via a namechange
- if !namechange && hhex != win.file.sha256 {
- return 0, errors.Errorf("file has been modified outside of poe")
- }
-
- n, err := f.WriteAt(win.body.text.buf.Bytes(), 0)
- if err != nil {
- return 0, err
- }
- f.Truncate(int64(n))
- f.Sync()
-
- win.file.sha256 = fmt.Sprintf("%x", sha256.Sum256(win.body.text.buf.Bytes()))
-
- info, err := f.Stat()
- if err != nil {
- return n, err
- }
- win.file.mtime = info.ModTime()
-
- win.body.dirty = false
-
- return n, nil
-}
-
-// Name returns either the file from disk name or empty string if the buffer has no disk counterpart.
-func (win *Window) Name() string {
- if win.file.name == FnEmptyWin {
- return FnEmptyWin
- }
- s := win.NameAbs()
- if strings.HasPrefix(s, baseDir) {
- s = "." + strings.TrimPrefix(s, baseDir)
- s = filepath.Clean(s)
- }
- return s
-}
-
-func (win *Window) NameAbs() string {
- if win.file.name == FnEmptyWin {
- return ""
- }
- s, _ := filepath.Abs(win.file.name)
- return s
-}
-
-func (win *Window) NameTag() string {
- tstr := win.tagline.text.String()
- if tstr == "" {
- return ""
- }
- return strings.Split(tstr, " ")[0]
-}
-
-// Dir returns the working directory of current window, without trailing path separator.
-func (win *Window) Dir() string {
- if win.isdir {
- return win.NameAbs()
- }
- if win.Name() == FnEmptyWin {
- return baseDir
- }
- return filepath.Dir(win.NameAbs())
-}
-
-// Flags returns the tagline flags for the window.
-//
-// modified: '
-func (win *Window) Flags() string {
- var flags string
- if win.body.dirty {
- flags += "'"
- }
- return flags
-}
-
-// Resize will set new values for position and width height. Meant to be used on a resize event for proper recalculation during the Draw().
-func (win *Window) Resize(x, y, w, h int) {
- win.x, win.y, win.w, win.h = x, y, w, h
-
- win.tagline.Resize(win.x+3, win.y, win.w-3, 1) // 3 for tagbox
- win.body.Resize(win.x, win.y+1, win.w, win.h-1)
-}
-
-func (win *Window) UnFocus() {
- win.body.focused = true
- win.tagline.focused = false
-}
-
-func (win *Window) HandleEvent(ev tcell.Event) {
- switch ev := ev.(type) {
- case *tcell.EventMouse:
- _, my := ev.Position()
-
- // Set focus to either tagline or body
- if my > win.tagline.y+win.tagline.h-1 {
- win.tagline.focused = false
- } else {
- win.tagline.focused = true
- }
- case *tcell.EventKey:
- switch ev.Key() {
- case tcell.KeyCtrlS: // save
- _, err := win.SaveFile()
- if err != nil {
- printMsg("%s\n", err)
- }
- return
- }
- }
-
- // Pass along the event down to current view, if we have not already done something and returned in the switch above.
- if win.tagline.focused {
- win.tagline.HandleEvent(ev)
- } else {
- win.body.HandleEvent(ev)
- }
-}
-
-func (win *Window) Draw() {
- // Draw tag square
- boxstyle := tagSquareStyle
- if win.body.dirty {
- boxstyle = tagSquareModifiedStyle
- }
- screen.SetContent(win.x, win.y, ' ', nil, boxstyle)
- screen.SetContent(win.x+1, win.y, ' ', nil, boxstyle)
- screen.SetContent(win.x+2, win.y, ' ', nil, win.tagline.style)
-
- // Tagline
- win.tagline.Draw()
-
- // Main text buffer
- win.body.Draw()
-}
-
-func (win *Window) CanClose() bool {
- ok := !win.body.dirty || win.qcnt > 0
- if !ok {
- name := win.Name()
- if name == FnEmptyWin {
- name = "unnamed file"
- }
- printMsg("%s modified\n", name)
- win.qcnt++
- }
- return ok
-}
-
-func (win *Window) Close() {
- if !win.CanClose() {
- return
- }
- win.col.CloseWindow(win)
-}