查看原始碼 IEx (IEx v1.16.2)
Elixir 的互動式 shell。
這裡描述的某些功能取決於您的終端。特別是,如果您收到一條消息說無法運行智能終端,這裡描述的一些功能將無法使用。
助手
IEx 提供了一系列助手。它們可以通過在 shell 中輸入 h()
或作為 IEx.Helpers
模組的文檔來訪問。
自動完成
要發現模組的公共函數或其他模組,請輸入模組名後跟一個句點,然後按 tab 觸發自動完成。例如
Enum.
一個模組可能導出不打算直接使用的函數:這些函數不會被 IEx 自動完成。IEx 不會自動完成帶有 @doc false
、@impl true
註釋的函數,或者未明確記錄並且函數名字以 __foo__
形式的函數。
自動完成在 Windows shells 的 Erlang/OTP 26 中默認可用。在較早的版本中,您可能需要在啟動 IEx 時傳遞 --werl
選項,例如 iex --werl
(如果使用 PowerShell,則為 iex.bat --werl
)。可以通過將 IEX_WITH_WERL
環境變量設置為 1
來永久啟用 --werl
。
編碼和著色
IEx 預期輸入和輸出以 UTF-8 編碼。這是大多數 Unix 終端的默認值,但在 Windows 上可能不是這種情況。如果您在 Windows 上運行並且看到打印的值不正確,您可能需要在調用 iex
(或者如果使用 PowerShell,則在調用 iex.bat
之前)運行 chcp 65001
以更改當前會話的編碼。
同樣,大多數 Unix 終端默認啟用 ANSI 着色。它們也可在 Windows 10 上的控制台和 Erlang/OTP 26 或更高版本上使用。對於早期的 Erlang/OTP 版本,您可以通過運行以下命令在註冊表中為當前用戶顯式啟用它
$ reg add HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1
在運行上述命令之後,您必須重新啟動當前的控制台。
Shell 歷史記錄
可以通過傳遞一些選項來啟用 VM 中的 shell 歷史記錄。這可以在啟動 IEx 時根據需要進行。
$ iex --erl "-kernel shell_history enabled"
如果您寧願將其在系統中全局啟用,則可以使用 ERL_AFLAGS
環境變量,並確保在您的終端/ shell 配置中設置相應的值。
在類 Unix / Bash 上
$ export ERL_AFLAGS="-kernel shell_history enabled"
在 Windows 上
$ set ERL_AFLAGS "-kernel shell_history enabled"
在 Windows 10 / PowerShell 上
$ $env:ERL_AFLAGS = "-kernel shell_history enabled"
IEx 中的表達式
作為交互式 shell,IEx 評估表達式。這有一些值得討論的有趣結果。
第一個是代碼是真正評估的,而不是編譯的。這意味著在 shell 中進行的任何基準測試都將產生偏差的結果。因此,永遠不要在 shell 中運行任何分析或基準測試。
其次,IEx 允許您將一個表達式分成多行,因為這在 Elixir 中很常見。例如
iex(1)> "ab
...(1)> c"
"ab\nc"
在上面的例子中,shell 將等待更多輸入,直到找到結束引號。有時候不明顯 shell 預期哪個字符,用戶可能會發現自己陷入未完成表達式狀態,無法終止它,除非退出 shell。
對於這種情況,有一個特殊的斷點觸發器(#iex:break
),當它在一行中被單獨遇到時,將強制 shell 中斷任何待處理的表達式並返回正常狀態
iex(1)> ["ab
...(1)> c"
...(1)> "
...(1)> ]
...(1)> #iex:break
** (TokenMissingError) iex:1: incomplete expression
將多行表達式粘貼到 IEx 中
IEx 以急切方式逐行評估其輸入。如果在一行的結尾處,到目前為止看到的代碼是完整的表達式,那麼 IEx 將在該點評估它。
iex(1)> [1, [2], 3]
[1, [2], 3]
為了防止這種行為破壞有效的代碼,其中後續行以二進制運算符開始,例如|>/2
或++/2
,IEx會自動將這些行視為前置了IEx.Helpers.v/0
的操作,該操作返回前一個表達式的值(如果有)。
iex(1)> [1, [2], 3]
[1, [2], 3]
iex(2)> |> List.flatten()
[1, 2, 3]
上述等同於
iex(1)> [1, [2], 3]
[1, [2], 3]
iex(2)> v() |> List.flatten()
[1, 2, 3]
如果歷史記錄中沒有前一個表達式,則管道運算符將失敗
iex(1)> |> List.flatten()
** (RuntimeError) v(-1) is out of bounds
如果前一個表達式是匹配操作,則管道運算符也將失敗,以防止未經請求的匹配中斷
iex(1)> x = 42
iex(2)> |> IO.puts()
** (SyntaxError) iex:2:1: pipe shorthand is not allowed immediately after a match expression in IEx. To make it work, surround the whole pipeline with parentheses ('|>')
|
2 | |> IO.puts()
| ^
請注意,上述對於+/2
和-/2
不起作用,因為它們與一元+/1
和-/1
具有二義性
iex(1)> 1
1
iex(2)> + 2
2
中斷菜單
在IEx中,按下Ctrl+C
將打開BREAK
菜單。在此菜單中,您可以退出shell,查看進程和ETS表信息等等。
退出shell
有幾種方法可以退出IEx shell
- 通過
BREAK
菜單(通過Ctrl+C
可用),輸入q
,然後按enter - 通過按下
Ctrl+C
,Ctrl+C
- 通過按下
Ctrl+\
如果您連接到遠程shell,則在斷開連接後它仍然保持活動狀態。
dbg
和斷點
IEx與Kernel.dbg/2
集成,並引入了一個可以暫停代碼執行的後端。要啟用它,您必須傳遞--dbg pry
$ iex --dbg pry
例如,請參考以下函數
def my_fun(arg1, arg2) do
dbg(arg1 + arg2)
... implementation ...
end
當代碼以 iex
執行時(通常通過調用 iex --dbg pry -S mix
),它將請求您允許使用 "pry"。如果您同意,它將在上述函數的上下文中啟動一個 IEx shell,可以訪問其變量、導入和別名。但是,您只能訪問現有值,無法訪問私有函數,也無法更改執行本身(因此命名為 "pry")。
當在管道的末尾使用 |> dbg()
時,您可以在管道的每一步進行檢查。您可以在需要時輸入 n
以跳轉到下一個管道。當您想要執行所有步驟但仍保持在檢查過程中時,請輸入 continue
。當您想要退出檢查過程並啟動新的 shell 時,請輸入 respawn
。
或者,您可以直接開始一個 pry 會話,而不使用 dbg/2
,通過調用 IEx.pry/0
。
IEx 還允許您設置斷點,以便在給定模塊、函數和您無法控制的參數上開始 pry 會話,通過 IEx.break!/4
。與 dbg()
中的管道類似,IEx.break!/4
允許您逐行調試函數並訪問其變量。但斷點不包含來自源代碼的導入和別名的信息。
在使用測試時使用 dbg
或斷點時,請記得將 --trace
傳遞給 mix test
,以避免遇到超時
$ iex -S mix test --trace
$ iex -S mix test path/to/file:line --trace
用戶切換命令
除了 BREAK
菜單外,您還可以輸入 Ctrl+G
來進入 User switch command
菜單。到達後,您可以輸入 h
以獲取更多信息。
在此菜單中,開發人員可以開始新的 shell 並在它們之間切換。讓我們試試看
User switch command
--> s 'Elixir.IEx'
--> c
上面的命令將啟動一個新的 shell 並連接到它。創建一個名為 hello
的新變量並為其賦值
hello = :world
現在,讓我們回到第一個 shell
User switch command
--> c 1
現在,再次嘗試訪問 hello
變量
hello
** (CompileError) undefined variable "hello"
上面的命令失敗了,因為我們切換了shell。由於各個shell是相互隔離的,所以無法從一個shell中訪問在另一個shell中定義的變量。
用戶切換命令
也可以用於終止現有的會話,例如當評估器陷入無限循環時,或者當您在輸入表達式時卡住時。
User switch command
--> i
--> c
用戶切換命令
菜單還允許開發人員使用 r
命令連接到遠程shell。這是我們接下來要討論的話題。
遠程shell
IEx 允許您以兩種方式連接到另一個節點。首先,我們只能在給出當前shell和要連接的shell的名稱的情況下連接到shell。
讓我們試一下。首先,啟動一個新的shell
$ iex --sname foo
iex(foo@HOST)1>
提示符括號中的字符串是您節點的名稱。我們可以通過調用 node/0
函數來檢索它
iex(foo@HOST)1> node()
:"foo@HOST"
iex(foo@HOST)2> Node.alive?()
true
為了好玩,讓我們在這個shell中定義一個簡單的模塊
iex(foo@HOST)3> defmodule Hello do
...(foo@HOST)3> def world, do: "it works!"
...(foo@HOST)3> end
現在,讓我們再啟動另一個shell,同樣給它一個名字
$ iex --sname bar
iex(bar@HOST)1>
如果我們嘗試調用 Hello.world/0
,它將不可用,因為它僅在另一個shell中定義
iex(bar@HOST)1> Hello.world()
** (UndefinedFunctionError) undefined function Hello.world/0
但是,我們可以遠程連接到另一個shell。打開 User switch command
提示符(Ctrl+G)並輸入
User switch command
--> r 'foo@HOST' 'Elixir.IEx'
--> c
現在我們已經連接到遠程節點了,因為提示符向我們顯示,我們可以訪問在那裡定義的信息和模塊
iex(foo@HOST)1> Hello.world()
"it works!"
事實上,連接到遠程shell是如此常見,我們也通過命令行提供了一個快捷方式
$ iex --sname baz --remsh foo@HOST
其中 "remsh" 意思是 "remote shell"。通常,Elixir 支持
- 從一個Elixir節點到另一個Elixir節點的remsh
- 從一個普通的Erlang節點到一個Elixir節點的remsh(通過^G菜單)
- 從一個Elixir節點到一個普通的Erlang節點的remsh(並在那裡獲得一個
erl
shell)
不支持將一個Elixir shell連接到沒有Elixir的遠程節點。
.iex.exs 文件
開始時,IEx 會尋找本地的 .iex.exs
檔案(位於目前的工作目錄中),然後尋找全局的 .iex.exs
檔案,該檔案位於由 IEX_HOME
環境變數指定的目錄內(預設為 ~
),並加載找到的第一個(如果有的話)。
所選擇的 .iex.exs
檔案中的代碼會在 shell 的上下文中逐行評估,就好像每行都在 shell 中輸入一樣。例如,.iex.exs
檔案中加載的任何模塊或綁定的變量將在啟動後的 shell 中可用。
請參閱以下 .iex.exs
檔案
# Load another ".iex.exs" file
import_file("~/.iex.exs")
# Import some module from lib that may not yet have been defined
import_if_available(MyApp.Mod)
# Print something before the shell starts
IO.puts("hello world")
# Bind a variable that'll be accessible in the shell
value = 13
在上述 .iex.exs
檔案所在的目錄中運行 IEx 將會產生
$ iex
Erlang/OTP 24 [...]
hello world
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> value
13
可以通過為 IEx 提供 --dot-iex
選項來加載另一個檔案。請參閱 iex --help
。
對於遠程節點,.iex.exs
檔案的位置是相對於啟動應用程序的用戶,而不是相對於遠程 IEx 連接的用戶。
配置 shell
IEx 提供了一些自定義選項。通過輸入 h IEx.configure/1
來查看 IEx.configure/1
函數的文檔。
這些選項可以在您的項目配置文件中配置,也可以通過從您的 ~/.iex.exs
檔案中調用 IEx.configure/1
進行全局配置。例如
# .iex.exs
IEx.configure(inspect: [limit: 3])
現在運行 shell
$ iex
Erlang/OTP 24 [...]
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> [1, 2, 3, 4, 5]
[1, 2, 3, ...]
總結
功能
基於宏的快捷方式,用於 IEx.break!/4
。
設置在給定數量的 stops
中的 module
、function
和 arity
中的斷點。
返回使用指定 color
轉義的 string
。
返回 IEx 配置。
配置 IEx。
返回用於檢查的選項。
查看進程環境。
如果 IEx 已啟動則返回 true
,否則返回 false
。
返回用於打印的 IEx 寬度。
函數
基於宏的快捷方式,用於 IEx.break!/4
。
@spec break!(module(), atom(), arity(), non_neg_integer()) :: IEx.Pry.id()
設置在給定數量的 stops
中的 module
、function
和 arity
中的斷點。
此函數將對給定的模組進行儀器化,並在記憶體中加載新版本,並在給定的函數和參數性上進行逐行斷點。如果重新編譯模組,則所有斷點都將丟失。
當達到斷點時,IEx 將詢問您是否要 pry
給定的函數和參數性。換句話說,這與 IEx.pry/0
類似,因為運行過程變成了 IEx 命令的評估器,並且暫時更改為具有自定義組領導者。但是,與 IEx.pry/0
不同,來源代碼中的別名和導入在 shell 中不可用。
IEx 助手包括與斷點相關的許多方便功能。下面列出了完整的模塊,例如 IEx.Helpers.breaks/0
,但請記住,它可以在 IEx 中直接調用為 breaks()
。它們是
IEx.Helpers.break!/2
- 為給定的Mod.fun/arity
設置斷點IEx.Helpers.break!/4
- 為給定模組、函數和參數性設置斷點IEx.Helpers.breaks/0
- 列印所有斷點及其 IDIEx.Helpers.continue/0
- 在同一個 shell 中繼續到下一個斷點IEx.Helpers.n/0
- 轉到當前斷點的下一行IEx.Helpers.next/0
- 與上述相同IEx.Helpers.open/0
- 在當前斷點上打開編輯器IEx.Helpers.remove_breaks/0
- 刪除所有模組中的所有斷點IEx.Helpers.remove_breaks/1
- 刪除給定模組中的所有斷點IEx.Helpers.reset_break/1
- 設置給定 ID 的停止次數為零IEx.Helpers.reset_break/3
- 將給定模組、函數、arity 的停止次數設置為零IEx.Helpers.respawn/0
- 啟動新的 shell(斷點將再次要求許可)IEx.Helpers.whereami/1
- 顯示當前位置
默認情況下,斷點中的停止次數為 1。除非設置另一個斷點,否則任何後續調用都不會停止代碼執行。
或者,可以通過傳遞 stops
參數來增加停止次數。可以使用 IEx.Helpers.reset_break/1
和 IEx.Helpers.reset_break/3
來將停止次數重置為零。請注意,即使在所有斷點上的所有停止都被消耗後,模組仍然保持“儀器化”。您可以通過調用 IEx.Helpers.remove_breaks/1
在給定模組上刪除儀器化,在所有模組上刪除斷點。
在斷點內部,可以調用 n
跳轉到下一行。要退出斷點,可以調用 continue
,它將阻塞 shell,直到找到下一個斷點或進程終止,或者調用 respawn
,它將啟動一個新的 IEx shell,釋放原始 shell。
示例
以下示例將使用 break!
,假設您直接從您的 IEx shell 設置斷點。但您可以通過使用完全限定名稱 IEx.break!
在任何地方設置斷點。
以下將在 URI.parse/1
上設置斷點
break! URI, :parse, 1
此調用將設置一個停止一次的斷點。要設置一個停止 10 次的斷點
break! URI, :parse, 1, 10
IEx.break!/2
是一個方便的宏,允許以 Mod.fun/arity
格式給出斷點
break! URI.parse/1
或者設置一個停止 10 次的斷點
break! URI.parse/1, 10
此函數返回斷點 ID,如果設置斷點時出錯,則會引發異常。
模式和守衛
IEx.break!/2
允許給出模式,只在某些情況下觸發斷點。例如,只有當第一個參數以“https”字符串開頭時才觸發斷點
break! URI.parse("https" <> _, _)
每個函數只能設置一個斷點。因此,如果多次使用不同模式調用 IEx.break!
,則只保留最後一個模式。
巨集
儘管可以在巨集中設置斷點,但請記住,巨集通常在編譯時擴展,因此它們在運行時可能永遠不會被調用。同樣,儘管可以給巨集設置模式,但巨集接收的是 AST,而不是值。例如,如果您嘗試在以下模式上中斷巨集
break! MyModule.some_macro(pid) when pid == self()
這個斷點永遠不會被觸發,因為巨集永遠不會收到 PID。即使您將巨集呼叫為 MyModule.some_macro(self())
,巨集將收到代表 self()
調用的 AST,而不是 PID 本身。
斷點和 mix test
在測試期間使用 IEx.break!/4
,您需要在 iex
命令中運行 mix
,並在 mix test
中傳遞 --trace
以避免遇到超時問題
$ iex -S mix test --trace
$ iex -S mix test path/to/file:line --trace
返回使用指定 color
轉義的 string
。
字符串中的 ANSI 转义并不会以任何方式进行处理。
@spec configuration() :: keyword()
返回 IEx 配置。
@spec configure(keyword()) :: :ok
配置 IEx。
支持的選項包括
:colors
:inspect
:width
:history_size
:default_prompt
:continuation_prompt
:alive_prompt
:alive_continuation_prompt
:parser
這些選項在下面的各節中分別討論。
顏色
封裝了 shell 使用的所有顏色設置的關鍵字列表。請參閱 IO.ANSI
模塊的文檔以查看支持的顏色和屬性列表。
關鍵字列表中支持的鍵列表
:enabled
- 允許開啟或關閉著色的布林值:eval_result
- 表達式結果值的顏色:eval_info
- ... 各種信息消息:eval_error
- ... 錯誤消息:eval_interrupt
- ... 中斷消息:stack_info
- ... 堆棧跟踪的顏色:blame_diff
- ... 當源代碼無匹配時歸咎於的選項:ls_directory
- ... 用於目錄條目 (ls 助手):ls_device
- ... 用於設備條目 (ls 助手)
在打印文檔時,IEx 也會將 Markdown 文檔轉換為 ANSI。這些顏色可以通過配置進行設置
:doc_code
- 代碼塊的屬性 (青色,明亮):doc_inline_code
- 內聯代碼 (青色):doc_headings
- h1 和 h2 (黃色,明亮):doc_title
- 輸出的整體標題 (反轉,黃色,明亮):doc_bold
- (明亮):doc_underline
- (下劃線)
IEx 還會使用 :syntax_colors
選項對檢查表達式進行顏色設置。可以通過以下方式禁用該功能
IEx.configure(colors: [syntax_colors: false])
您也可以按需配置語法顏色。以下示例將原子格式化為紅色,並將其他數據類型的顏色設置為無
IEx.configure(colors: [syntax_colors: [atom: :red]])
默認值可以在 IO.ANSI.syntax_colors/0
中找到。
檢查
包含 shell 在打印表達式評估結果時使用的檢查選項的關鍵字列表。默認為漂亮格式化,限制為 50 條目。
要顯示所有條目,請將限制配置為 :infinity
IEx.configure(inspect: [limit: :infinity])
請參閱 Inspect.Opts
以獲取完整的選項列表。
寬度
一個整數,表示輸出中要使用的最大列數。默認值為 80 列。實際輸出寬度是此數字和 :io.columns
結果的最小值。這樣您可以將 IEx 配置為您的最大屏幕尺寸,並始終佔用當前終端屏幕的全寬。
歷史記錄大小
要保留的表達式及其結果的數量。該值是一個整數。當它為負數時,歷史記錄是無限的。
提示
這是決定等待輸入時顯示給使用者的提示選項。
該值是一個關鍵字列表,包含兩個可能的鍵,表示提示類型
:default_prompt
- 當Node.alive?/0
返回false
時使用:continuation_prompt
- 當Node.alive?/0
返回false
且需要更多輸入時使用:alive_prompt
- 當Node.alive?/0
返回true
時使用:alive_continuation_prompt
- 當Node.alive?/0
返回true
且需要更多輸入時使用
提示字串中的以下值將被適當地替換
%counter
- 歷史索引%prefix
- 由IEx.Server
給定的前綴%node
- 本地節點的名稱
解析器
這是決定用於 IEx 的解析器的選項。
解析器是一個 "mfargs",它是一個具有三個元素的元組:模塊名稱、函數名稱和要附加的額外參數。解析器至少接收三個參數,當前輸入作為字符串,解析選項作為關鍵字列表,以及緩衝區作為字符串。它必須返回 {:ok, expr, buffer}
或 {:incomplete, buffer}
。
如果解析器引發異常,則緩衝區將重置為空字符串。
@spec inspect_opts() :: keyword()
返回用於檢查的選項。
查看進程環境。
此函數用於調試特定塊的代碼時,由特定進程執行。該進程成為 IEx 命令的評估器,並暫時更改為具有自定義群組領導者。通過調用 IEx.Helpers.respawn/0
來恢復這些值,它開始一個新的 IEx shell,釋放被窺視的那個。
當進程被窺視時,所有代碼都在 IEx 內運行,並且可以訪問原始代碼的所有導入和別名。但是,您無法更改代碼的執行方式,也無法訪問被窺視模塊的私有函數。模塊函數仍然需要通過 Mod.fun(args)
訪問。
另請參見 break!/4
以了解其他窺視方式。
dbg/0
整合透過呼叫
iex --dbg pry
,iex
將此函式設定為dbg/0
呼叫的預設後端。
範例
假設您想要調查某個特定函式正在發生的情況。通過從該函式調用 IEx.pry/0
,IEx 將允許您訪問其綁定(變數),驗證其詞法資訊並訪問進程資訊。讓我們看一個例子
import Enum, only: [map: 2]
defmodule Adder do
def add(a, b) do
c = a + b
require IEx; IEx.pry()
end
end
當調用 Adder.add(1, 2)
時,您將在您的 shell 中收到一條消息,要求進入給定的環境。通過允許它,shell 將被重置,您將可以訪問從上面獲得的所有變數和詞法作用域
iex(1)> map([a, b, c], &IO.inspect(&1))
1
2
3
請注意,IEx.pry/0
在調用進程中運行,會在評估循環期間阻塞該調用者。調用者進程可以通過調用 respawn/0
來釋放,該函數開始一個新的 IEx 評估循環,讓此進程繼續進行
iex(2)> respawn()
true
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
在 IEx 中設定變數或匯入模塊不會影響調用者的環境。然而,發送和接收訊息將改變進程狀態。
Pry 和巨集
當在由巨集定義的程式碼中設置 Pry 時,例如
defmacro __using__(_) do
quote do
def add(a, b) do
c = a + b
require IEx; IEx.pry()
end
end
end
由於引用表達式中的衛生機制,quote
內定義的變數在進行 prying 時將不可用。衛生機制會更改引用表達式中的變數名稱,以使其不與巨集的使用者定義的變數發生衝突。因此,原始名稱不可用。
Pry 和 mix test
在測試期間使用IEx.pry/0
,您需要在iex
命令中運行mix
,並將--trace
傳遞給mix test
,以避免超時
$ iex -S mix test --trace
$ iex -S mix test path/to/file:line --trace
@spec started?() :: boolean()
如果 IEx 已啟動則返回 true
,否則返回 false
。
這意味著IEx應用程式已啟動,但其命令列介面未運行。
@spec width() :: pos_integer()
返回用於打印的 IEx 寬度。
被助手使用,並且具有默認的最大字符上限為80個字符。