| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | package readline | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bufio" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 	"github.com/emirpasic/gods/v2/lists/arraylist" | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type History struct { | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 	Buf      *arraylist.List[string] | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	Autosave bool | 
					
						
							|  |  |  | 	Pos      int | 
					
						
							|  |  |  | 	Limit    int | 
					
						
							|  |  |  | 	Filename string | 
					
						
							|  |  |  | 	Enabled  bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewHistory() (*History, error) { | 
					
						
							|  |  |  | 	h := &History{ | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 		Buf:      arraylist.New[string](), | 
					
						
							| 
									
										
										
										
											2023-12-16 06:07:34 +08:00
										 |  |  | 		Limit:    100, // resizeme
 | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 		Autosave: true, | 
					
						
							|  |  |  | 		Enabled:  true, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := h.Init() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return h, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *History) Init() error { | 
					
						
							|  |  |  | 	home, err := os.UserHomeDir() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	path := filepath.Join(home, ".ollama", "history") | 
					
						
							| 
									
										
										
										
											2023-11-27 04:59:04 +08:00
										 |  |  | 	if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	h.Filename = path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-16 06:25:12 +08:00
										 |  |  | 	f, err := os.OpenFile(path, os.O_CREATE|os.O_RDONLY, 0o600) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if errors.Is(err, os.ErrNotExist) { | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer f.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	r := bufio.NewReader(f) | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		line, err := r.ReadString('\n') | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-03-15 22:14:12 +08:00
										 |  |  | 			if errors.Is(err, io.EOF) { | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		line = strings.TrimSpace(line) | 
					
						
							|  |  |  | 		if len(line) == 0 { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 		h.Add(line) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | func (h *History) Add(s string) { | 
					
						
							|  |  |  | 	h.Buf.Add(s) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	h.Compact() | 
					
						
							| 
									
										
										
										
											2023-10-28 11:38:03 +08:00
										 |  |  | 	h.Pos = h.Size() | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	if h.Autosave { | 
					
						
							| 
									
										
										
										
											2023-12-16 06:07:34 +08:00
										 |  |  | 		_ = h.Save() | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *History) Compact() { | 
					
						
							|  |  |  | 	s := h.Buf.Size() | 
					
						
							|  |  |  | 	if s > h.Limit { | 
					
						
							| 
									
										
										
										
											2024-05-22 13:21:04 +08:00
										 |  |  | 		for range s - h.Limit { | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 			h.Buf.Remove(0) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *History) Clear() { | 
					
						
							|  |  |  | 	h.Buf.Clear() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | func (h *History) Prev() (line string) { | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	if h.Pos > 0 { | 
					
						
							|  |  |  | 		h.Pos -= 1 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 	line, _ = h.Buf.Get(h.Pos) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	return line | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | func (h *History) Next() (line string) { | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	if h.Pos < h.Buf.Size() { | 
					
						
							|  |  |  | 		h.Pos += 1 | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 		line, _ = h.Buf.Get(h.Pos) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return line | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *History) Size() int { | 
					
						
							|  |  |  | 	return h.Buf.Size() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (h *History) Save() error { | 
					
						
							|  |  |  | 	if !h.Enabled { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tmpFile := h.Filename + ".tmp" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-19 02:53:51 +08:00
										 |  |  | 	f, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC|os.O_APPEND, 0o600) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer f.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf := bufio.NewWriter(f) | 
					
						
							| 
									
										
										
										
											2024-05-22 13:21:04 +08:00
										 |  |  | 	for cnt := range h.Size() { | 
					
						
							| 
									
										
										
										
											2024-12-21 16:02:50 +08:00
										 |  |  | 		line, _ := h.Buf.Get(cnt) | 
					
						
							|  |  |  | 		fmt.Fprintln(buf, line) | 
					
						
							| 
									
										
										
										
											2023-10-26 07:41:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	buf.Flush() | 
					
						
							|  |  |  | 	f.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err = os.Rename(tmpFile, h.Filename); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |