@@ -163,6 +163,28 @@ func Update(m model.Model, cfg config.Config, msg tea.Msg) (model.Model, tea.Cmd
163163 return HandleLogGraphKey (m , msg )
164164 }
165165
166+ if m .CurrentView == model .DiffView {
167+ switch msg .String () {
168+ case "esc" :
169+ m .CurrentView = model .FileView
170+ m .DiffLines = nil
171+ m .DiffViewOffset = 0
172+ return m , nil
173+ case "up" , "k" :
174+ if m .DiffViewOffset > 0 {
175+ m .DiffViewOffset --
176+ }
177+ return m , nil
178+ case "down" , "j" :
179+ if m .DiffViewOffset < len (m .DiffLines )- 1 {
180+ m .DiffViewOffset ++
181+ }
182+ return m , nil
183+ default :
184+ return m , nil
185+ }
186+ }
187+
166188 if m .CurrentView == model .MergeView {
167189 return handlers .HandleMergeView (m , msg )
168190 }
@@ -602,6 +624,44 @@ func Update(m model.Model, cfg config.Config, msg tea.Msg) (model.Model, tea.Cmd
602624 m .Message = "⚠ No files to stage"
603625 m .MessageType = "warning"
604626 }
627+ case "u" :
628+ hasStaged := false
629+ for _ , f := range m .Files {
630+ if f .Staged {
631+ hasStaged = true
632+ break
633+ }
634+ }
635+ if hasStaged {
636+ currentFileName := ""
637+ if m .Cursor < len (m .Files ) {
638+ currentFileName = m .Files [m .Cursor ].Name
639+ }
640+ for i := range m .Files {
641+ if m .Files [i ].Staged {
642+ m .Files [i ].Staged = false
643+ git .Reset (m .Files [i ].Name )
644+ }
645+ }
646+ m .Message = "✓ All files unstaged"
647+ m .MessageType = "success"
648+ files , _ := git .GetModifiedFiles ()
649+ m .Files = files
650+ if currentFileName != "" {
651+ for i , file := range m .Files {
652+ if file .Name == currentFileName {
653+ m .Cursor = i
654+ break
655+ }
656+ }
657+ }
658+ if m .Cursor >= len (m .Files ) && len (m .Files ) > 0 {
659+ m .Cursor = len (m .Files ) - 1
660+ }
661+ } else {
662+ m .Message = "⚠ No staged files to unstage"
663+ m .MessageType = "warning"
664+ }
605665 case "c" :
606666 ok := false
607667 for _ , f := range m .Files {
@@ -680,6 +740,20 @@ func Update(m model.Model, cfg config.Config, msg tea.Msg) (model.Model, tea.Cmd
680740 m .Message = "⚠ No file selected or no files available"
681741 m .MessageType = "warning"
682742 }
743+ case "d" :
744+ if len (m .Files ) > 0 && m .Cursor < len (m .Files ) {
745+ file := m .Files [m .Cursor ]
746+ diff , err := git .GetFileDiff (file .Name , file .Staged )
747+ if err != nil {
748+ m .Message = fmt .Sprintf ("✗ Error getting diff: %s" , err )
749+ m .MessageType = "error"
750+ } else {
751+ m .DiffLines = strings .Split (diff , "\n " )
752+ m .DiffViewOffset = 0
753+ m .CurrentView = model .DiffView
754+ }
755+ return m , nil
756+ }
683757 case "?" :
684758 if m .CurrentView == model .FileView {
685759 m .CurrentView = model .HelpView
@@ -753,6 +827,19 @@ func Update(m model.Model, cfg config.Config, msg tea.Msg) (model.Model, tea.Cmd
753827 if msg .Err == nil {
754828 m .HasRemoteChanges = msg .HasChanges
755829 }
830+
831+ case messages.MessageClearMsg :
832+ if msg .MessageID == m .MessageID {
833+ m .Message = ""
834+ m .MessageType = ""
835+ }
836+ return m , nil
837+ }
838+
839+ // Auto-clear messages after 3 seconds
840+ if m .Message != "" {
841+ m .MessageID ++
842+ cmds = append (cmds , async .PerformMessageClear (m .MessageID ))
756843 }
757844
758845 if len (cmds ) > 0 {
0 commit comments