What have you found for these years?

2011-06-27

終於解了我 bash 一直以來的問題之一

在這裡跟被我灌上 dev-tool 的電腦的使用者說聲抱歉,
游標亂跳的問題,我終於把他修好了 XD 接下來要記得一台台要來升級...
啊不過我可能得先搞定 xterm-color256 的問題,mac 內建的不支援...

事情是這樣的,我之前寫的 prompt.rb, 有漂亮顏色和 git 資訊的
command prompt 用在 bash 上,一直有因為顏色的關係,游標會有
很怪異的狀況,好像看不到的 character 也被算進輸出寬度的狀況,
於是 command 太長時就會出現很怪異的狀況。

這個我一直不知道要怎麼修,而我自己是用 fish 完全沒問題,就...
懶得管他了,想說是 bash 的 bug, 因為我根本 google 不到解法。
就跟 javascript 一樣,bash 也是個太多人用的東西,結果就是很難
查到比較細節,或是說比較技術細節的東西。不管我怎麼查 command
color prompt, 都得不到我要的答案。查出來的都是我早知道的廢話。

就是為什麼不管是 PROMPT_COMMAND 或 PS1 都無法正確處理
顏色的寬度。我一直在想,是不是我色碼用錯了?

前幾天,因為要用 rvm, 逼不得已只好又去用 bash, 然後一用 bash
我就受不了了,這天殺的游標問題不處理好真的沒辦法用。今天碰巧
查了看 git-prompt 是怎麼做的。抓下來一試,還真的就很正常。
可是他的 bash script 又太長了,我又看不懂,不知道關鍵到底在哪。
在那邊 tput setaf 什麼的試半天好像也沒什麼差...

最後火大,把他的結果像這樣輸出:

echo PS1 | ruby -e 'p $stdin.read'

然後把輸出結果塞到 PS1 裡看看,還真的就可以了。也就是說,重點
就在這個輸出裡,而不是什麼神秘的設定。我一直以為要用某些神秘的
程式控制寬度...

最後總算發現重點在於要用 \[ 和 \] 把色碼夾起來,這樣看起來 bash
就會把中間的東西當做沒有長度的 characters!! 也因此,這樣連 256 色
都解決了。反倒是 fish 自己無法正確處理 256 色,也就是說 bash 現在
反而有比 fish 還要好的結果 =_=b

不過還真是用「無數」小時換來的。這個問題,我搞不好有 google 和
亂試了超過十個小時還無法解決。又不知道可以問誰,誰懂 bash 啊 :x
是說應該可以去 irc 或 mailing list 問,但又很懶得描述這個問題...
只想一味責怪 bash 實在很有問題。

雖然說結果相當完美,但我仍然想說 bash 真的很有問題。只有 PS1 有
辦法用這種方式讓色碼沒有長度,PROMPT_COMMAND 一點效果也沒。
試半天後,總算發現這種方式可以順利運作,從 git-prompt.sh 學來的:
(心裡一直在納悶,這樣多此一舉是在幹嘛,而且從 ruby 裡根本改不到 PS1)

bash_prompt(){ PS1=`prompt.rb`; }
export PROMPT_COMMAND=bash_prompt
感覺真的很笨啊!!哪像 fish 就是一個 fish_prompt function,
搞定他就是搞定了,色碼長度也會自己偵測。唉,是說也許 bash
這樣做才是對的,因為誰知道會不會有其他 terminal 做自己的色碼?
因此到底要忽略哪些字元寬度,其實應該要是 user defined.
像是,fish 我還是查不到要怎麼讓 256 色能正確運作.......
我懷疑這很可能是寫死在 c 裡面的,所以除非去 patch fish...

重點是,PS1 和 PROMPT_COMMAND 運作模式有差,實在很難搞懂。
還有一堆奇奇怪怪的地方,fish 都是完全符合直覺,而 bash 就是很詭異,
很難用一個原則去解釋。然後 google 查東西又超難查的 :s

bash hate! long live fish!! ... 可惜 fish 感覺根本沒在開發了 :x
要不是我真的不太懂 shell, terminal, tty 諸如此類的運作,還真想
把 fish 很多很明顯有缺陷的東西一一修好 :(
應該是比擴充和改善 bash 容易多了...


至於 ruby shell 嘛,想來有趣,但... 路途太遙遠了 XD

3 retries:

Buganini said...
This comment has been removed by the author.
Buganini said...

shell就是一般普通的R-E-P-L程式
terminal跟tty負責輸出和輸入
也就是說terminal依據ansi control sequence和內容畫出顏色/文字,並處理游標移動和捲動
tty則是把鍵盤輸入轉成keyvalue(如一般英文字母)或ansi control sequence(如方向鍵或一些組合鍵)

但tty有時候也指I/O pair,講到pty的時候就是指I/O pair了

256色的色碼是有標準的(好像只有xterm?),bash要特別加[]我猜可能是parser不夠力,無法自動判斷出那是control sequence還是其他東西,所以無法判斷正確length以至於無法送正確的cursor position給terminal(\e[m;nH這種control sequence)

Lin Jen-Shin (godfat) said...

感謝 <(_ _)>
我以為 tty 是 output 給 terminal 的 device...
/dev 底下一大堆各式各樣的 tty @@"

至於 256 色,就我看 wikipedia 是只看到 xterm
另外我記得我之前明明就有看到另一種輸出 256 色的號碼,
可是現在卻找不到了,真是奇怪。記得不同 terminal 效果也不太一樣

不過 bash 都發展多久了... 不免在猜想,
是不是他覺得有些 control sequence 其實應該要有顯示長度的?
但都叫 "control" 了,總還是覺得哪裡怪怪的。
比方說,像是跳游標位置的 control sequence,
難道也會有顯示寬度嗎? :s
這些難道不是都有標準? "ANSI" control sequence...
那麼這麼做的理由是?還是單純為了 compatibility?
是可以理解 shell 這種東西不宜改變.......

Post a Comment

All texts are licensed under CC Attribution 3.0