Có cái gì đó giống như đóng cửa cho zsh?


7

Tôi vừa quyết định thử zsh (thông qua oh-my-zsh), và hiện đang chơi với precmdđể mô phỏng một dấu nhắc hai dòng có lời nhắc đúng trong nhiều hơn chỉ dòng cuối cùng.

Vì vậy, tôi đã sao chép chủ đề mặc định và lấy cảm hứng từ bài đăng này (rằng tôi cũng đang sử dụng để học hỏi rất nhiều), tôi thực hiện một số cách như thế này (tôi sẽ thêm màu sau):

function precmd {
    local cwd="${(%):-[%~]}"
    local who_where="${(%):-%n@%m}"
    local git_info=${(%)$(git_prompt_info)}
    local right_prompt="     $git_info [$who_where]"
    local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"

    echo "$left_prompt$right_prompt"
}

Và nó hoạt động. Nhưng tôi không thể không tự hỏi: zsh có xác định tất cả các biến đó mỗi khi tiền tố được gọi không?

Tôi đã googling cho các bao đóng, phạm vi và không gian tên liên quan đến zsh, tìm cách gắn các vars cục bộ dưới dạng dữ liệu vào premd, vì vậy nó không cần xác định lại các biến mỗi lần, nhưng tôi không tìm thấy gì. Có cách nào để làm những gì tôi đang cố gắng không, hay tôi nên bỏ nó đi?

Là một lưu ý phụ, và chỉ khi nó có liên quan, "để có chức năng được tải" nghĩa là gì?

Câu trả lời:


10

Zsh không có bất cứ thứ gì như bao đóng hoặc gói hoặc không gian tên. Zsh thiếu một loạt những thứ cần thiết để có sự đóng cửa thực sự:

  • Chức năng không phải là hạng nhất. Bạn không thể truyền các hàm xung quanh dưới dạng đối số cho các hàm khác và các hàm không thể trả về các hàm khác. (Bạn có thể chuyển tên của hàm để gọi, nhưng điều đó không giống với việc truyền chính hàm đó).

  • Bạn không thể có các hàm lồng nhau. Tất cả các chức năng trong zsh là toàn cầu. Bạn phải đặt tiền tố tên hàm của bạn để tránh xung đột. Đặc biệt lưu ý rằng các chức năng sẽ phủ bóng các chương trình bên ngoài có cùng tên. Nếu bạn có một hàm được gọi ls, nó sẽ được gọi thay vì chương trình ls. Điều này có thể hữu ích, trừ khi bạn làm điều đó một cách tình cờ.

  • Các biến được phạm vi động, không có phạm vi tĩnh như trong hầu hết các ngôn ngữ hiện đại. Ngay cả khi bạn có thể có các hàm lồng nhau, các hàm bên trong sẽ không đóng các biến cục bộ của các hàm ngoài theo cách bạn thường mong đợi. Bạn không thể sử dụng chúng để tạo các mô-đun theo cách mọi người thực hiện, giả sử, Javascript.

  • Zsh không có chức năng ẩn danh, nhưng không có bất kỳ thứ gì khác, chúng không hữu ích cho lắm.

Về cơ bản, điều tốt nhất bạn có thể làm là tiền tố tất cả các hàm và biến toàn cục của bạn.

Tôi cũng sẽ chỉ ra rằng bạn nên xác định precmdnhư thế này:

% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function

add-zsh-hookcho phép bạn nối chức năng của mình vào precmdmà không ghi đè bất kỳ chức năng nào khác có thể muốn nối precmd.

Ý nghĩa của việc tải một hàm là một câu hỏi riêng biệt. Zsh có tính năng tự động tải, chỉ tải các chức năng từ đĩa khi chúng thực sự được gọi. Khi bạn làm điều đó autoload -Uz foobar, làm cho chức năng có tên foobarđể gọi. Khi bạn thực sự gọi foobar, điều đó tải định nghĩa từ đĩa.


1
Đây là những gì tôi đang tìm kiếm. Tôi chưa thể bỏ phiếu, nhưng kudos.
ferhtgoldaraz

@Matt, tín dụng bổ sung cho việc đề cập đến add-zsh-hook.
SuperMagic

Đối với điểm 1, bạn có thể vượt qua định nghĩa của một hàm như là đối số: myfunc $functions[otherfunction]đó myfunccó thể gọi ví dụ như () {eval $1} args(không phải là tôi sẽ khuyên bạn nên làm điều đó mà).
Stéphane Chazelas

Đối với điểm 3, bạn có thể có phạm vi tĩnh bằng cách sử dụng privatecác biến (trong zsh/param/privatemô-đun).
Stéphane Chazelas

Tôi chỉ có ý tưởng điên rồ này và dường như nó không chỉ hoạt động với bash mà còn zsh: gist.github.com/pinkeen/287ad64d951f7bf138afce975d3bce7b
pinkeen

5

Không, đóng cửa quá phức tạp cho zsh. Zsh được thiết kế để giải thích các tập lệnh nhỏ không bị loại bỏ khỏi tương tác trực tiếp. Nó không có các tính năng ngôn ngữ ưa thích, rất hữu ích để lập trình trong quy mô lớn nhưng ít hơn đối với loại tác vụ nhỏ mà shell thường được sử dụng.

Lưu ý rằng nếu có một số dạng đóng cho phép giá trị của các biến được tính toán trước một lần và sau đó được lưu trữ, thì các giá trị sẽ không được cập nhật khi có gì đó thay đổi khiến thông tin trở nên không hợp lệ.

$git_infovà các biến dẫn xuất có thể thay đổi bất cứ lúc nào do sửa đổi tệp được kiểm tra thành git hoặc kho lưu trữ git. Vì vậy, họ cần phải được tính toán lại mỗi lần.

Bạn có thể lưu trữ các giá trị của cwdwho_wheretrong một biến toàn cục, vì chúng không thay đổi trong hoạt động bình thường. cwdthay đổi khi thư mục hiện tại thay đổi, do đó nó sẽ cần được cập nhật từ đó chpwd. Tuy nhiên, các biến này cực kỳ nhanh chóng để tính toán, vì vậy không có gì phải bận tâm. Tính toán đắt tiền ở đây đang chạy git_prompt_info, và điều đó có thể thay đổi bất cứ lúc nào.

Khi bạn đang hiển thị thông tin giữa mỗi lệnh, có thể nên đặt nó như một phần của dấu nhắc ( PS1hoặc psvarmảng). Zsh biết rằng nó phải hiển thị lại lời nhắc trong nhiều tình huống, trong khi nó không biết gì về những gì bạn in từ đó precmd.


+1 để giải quyết nhu cầu tính toán lại các giá trị mỗi lần.
chepner

1

Có, các biến đó được xác định lại mỗi lần bạn gọi hàm.

Nếu bạn muốn khởi tạo chúng chỉ một lần, bạn có thể chỉ cần di chuyển chúng lên cấp cao nhất, ngoài chức năng.


Cảm ơn câu trả lời. Mặc dù tôi đang cố gắng tìm giải pháp thay thế cho việc sử dụng phạm vi toàn cầu để tôi có thể chống lại ô nhiễm trong tương lai nếu có nhu cầu. Có lẽ có một số thay thế cho điều này?
ferhtgoldaraz

1
Không hẳn vậy. Bạn có thể sử dụng tiền tố cho các biến của mình, giả sử là LRPROMPT_, để hạn chế va chạm / ô nhiễm tên có thể .... nhưng vẫn có thể. Ngoài ra, nó chỉ là vỏ của bạn và nhắc nhở. Va chạm có thể xảy ra, nhưng nó không phải là vấn đề lớn trừ khi bạn thực hiện nhiều hơn một chút trong vỏ so với có lẽ là hợp lý. Tôi sử dụng oh-my-zsh VÀ có hơn 2000 dòng trong cấu hình zsh tùy chỉnh (ngoài omz) và va chạm thực sự không phải là vấn đề. Tôi sử dụng tiền tố, mặc dù.
SuperMagic

Nếu các tệp khởi động shell của bạn quá lớn đến nỗi các xung đột tên thực sự là một vấn đề, bạn gần như chắc chắn sẽ có các vấn đề khác nghiêm trọng hơn :)
Ben

@Ben, con số đó bao gồm các hàm có khoảng trắng và biến cục bộ đáng kể. Nếu tôi có 2000 bí danh và biến toàn cục .... đó sẽ là một vấn đề.
SuperMagic
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.