github.com/ladydascalie/elvish@v0.0.0-20170703214355-2964dd3ece7f/store/cmd.go (about) 1 package store 2 3 import ( 4 "database/sql" 5 6 "github.com/elves/elvish/store/storedefs" 7 ) 8 9 func init() { 10 initDB["initialize command history table"] = func(db *sql.DB) error { 11 _, err := db.Exec(`CREATE TABLE IF NOT EXISTS cmd (content text)`) 12 return err 13 } 14 } 15 16 // NextCmdSeq returns the next sequence number of the command history. 17 func (s *Store) NextCmdSeq() (int, error) { 18 row := s.db.QueryRow(`SELECT ifnull(max(rowid), 0) + 1 FROM cmd`) 19 var seq int 20 err := row.Scan(&seq) 21 return seq, err 22 } 23 24 // AddCmd adds a new command to the command history. 25 func (s *Store) AddCmd(cmd string) (int, error) { 26 r, err := s.db.Exec(`INSERT INTO cmd (content) VALUES(?)`, cmd) 27 if err != nil { 28 return -1, err 29 } 30 i, err := r.LastInsertId() 31 return int(i), err 32 } 33 34 // Cmd queries the command history item with the specified sequence number. 35 func (s *Store) Cmd(seq int) (string, error) { 36 row := s.db.QueryRow(`SELECT content FROM cmd WHERE rowid = ?`, seq) 37 var cmd string 38 err := row.Scan(&cmd) 39 return cmd, err 40 } 41 42 // IterateCmds iterates all the commands in the specified range, and calls the 43 // callback with the content of each command sequentially. 44 func (s *Store) IterateCmds(from, upto int, f func(string) bool) error { 45 rows, err := s.db.Query(`SELECT content FROM cmd WHERE rowid >= ? AND rowid < ?`, from, upto) 46 if err != nil { 47 return err 48 } 49 defer rows.Close() 50 for rows.Next() { 51 var cmd string 52 err = rows.Scan(&cmd) 53 if err != nil { 54 break 55 } 56 if !f(cmd) { 57 break 58 } 59 } 60 return err 61 } 62 63 // Cmds returns the contents of all commands within the specified range. 64 func (s *Store) Cmds(from, upto int) ([]string, error) { 65 var cmds []string 66 err := s.IterateCmds(from, upto, func(cmd string) bool { 67 cmds = append(cmds, cmd) 68 return true 69 }) 70 return cmds, err 71 } 72 73 // NextCmd finds the first command after the given sequence number (inclusive) 74 // with the given prefix. 75 func (s *Store) NextCmd(from int, prefix string) (int, string, error) { 76 row := s.db.QueryRow(`SELECT rowid, content FROM cmd WHERE rowid >= ? AND substr(content, 1, ?) = ? ORDER BY rowid asc LIMIT 1`, from, len(prefix), prefix) 77 return convertCmd(row) 78 } 79 80 // PrevCmd finds the last command before the given sequence number (exclusive) 81 // with the given prefix. 82 func (s *Store) PrevCmd(upto int, prefix string) (int, string, error) { 83 var upto64 = int64(upto) 84 if upto < 0 { 85 upto64 = 0x7FFFFFFFFFFFFFFF 86 } 87 row := s.db.QueryRow(`SELECT rowid, content FROM cmd WHERE rowid < ? AND substr(content, 1, ?) = ? ORDER BY rowid DESC LIMIT 1`, upto64, len(prefix), prefix) 88 return convertCmd(row) 89 } 90 91 func convertCmd(row *sql.Row) (seq int, cmd string, err error) { 92 err = row.Scan(&seq, &cmd) 93 if err == sql.ErrNoRows { 94 err = storedefs.ErrNoMatchingCmd 95 } 96 return 97 }