这次能够成功,核心原因在于解决了 **"多进程状态隔离"** 导致的信息不对称问

这次能够成功,核心原因在于解决了 "多进程状态隔离" 导致的信息不对称问题。

简单来说:你启动 FSM 的那个进程,和负责处理按键的后台进程,其实是两个完全独立的"大脑"。

这里是详细的复盘分析:

1. 之前为什么失败?(大脑失联)

当你执行 tmux-fsm -enter 时:

  1. CLI 进程启动:它在自己的内存里把 FSMActive 设为 true,告诉 Tmux 设置 @fsm_active=1,然后进程结束销毁
  2. 后台 Daemon 进程:它一直在后台运行。它并没有收到通知说"我们进入 FSM 模式了"。在它的内存里,FSMActive 仍然是 false

导致的结果:

  • 当你按下 h,请求发给 Daemon。
  • Daemon 处理完 h 后,代码走到了这里:
    // 旧代码  if fsm.FSMActive {  // Daemon 觉得:我内存里这是 false 啊      reconcileFSMState(...) // 所以这行救命代码被跳过了!  }  
    
  • 与此同时,Tmux 处理完按键命令后,因为某些机制(比如焦点变化或命令结束),自动把键盘表切回了默认的 root
  • Daemon 没有去纠正它(因为它以为没在 FSM 模式)。
  • 你按第二次键时,已经是 root 模式了,所以直接上屏。

2. 这次为什么成功?(以 Tmux 为真理)

我们在 main.go 中去掉了 if 判断:

// 新代码  
// 不管 Daemon 内存里怎么想,无条件执行状态核对  
reconcileFSMState(actualClient)   

现在的流程是:

  1. 你按 h
  2. Daemon 处理完 h
  3. Daemon 被迫去运行 reconcileFSMState
  4. reconcileFSMState 实际上是去问 Tmux:

    "喂,Tmux,你的 @fsm_active 变量现在是 1 吗?"

  5. Tmux 回答:"是的,之前那个 CLI 进程把它设为 1 了"。
  6. reconcileFSMState 接着检查:"那你当前的 KeyTable 是 fsm 吗?"
  7. 如果 Tmux 说:"哎呀,我不小心切回 root 了"。
  8. reconcileFSMState 立即下令:"不行!给我切回 fsm!"

3. 那个空格的作用 (" @fsm_active")

之前 enter_exit.go 里多了一个空格:backend.GlobalBackend.SetUserOption(" @fsm_active", "1")

  • 这导致 Tmux 里设置了一个叫 " @fsm_active"(带空格)的变量。
  • 但是 reconcileFSMState 读取的是 "@fsm_active"(不带空格)。
  • 后果:即使逻辑通了,Daemon 去读变量时读到的是空值(0),它会以为 FSM 已经关闭了,从而主动帮你退出了 FSM 模式。

总结

这次成功的关键在于确立了唯一的真理来源 (Source of Truth)

  • 不再相信 Go 程序的内存变量(因为进程是分离的)。
  • 只相信 Tmux 的用户选项 (@fsm_active)
  • 并且每次按键后,都强制根据 Tmux 的变量值来"锁死"键盘表状态。