summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpportunityLiu <[email protected]>2019-06-05 14:17:11 +0800
committerOpportunityLiu <[email protected]>2019-06-05 14:17:11 +0800
commit1b5017a88667c5af7a4afd4311d4861eb540b1bb (patch)
tree926c7a07f0bae03d9c78dd94350834227828321d
parent06dba0daf4968b9632ebc00a9018c6af044422df (diff)
tab completion
-rw-r--r--scripts/get.ps1249
-rwxr-xr-xscripts/get.sh36
-rw-r--r--scripts/register-completions.bash16
-rw-r--r--scripts/register-completions.ps18
-rw-r--r--scripts/register-completions.zsh10
-rw-r--r--xmake/core/sandbox/modules/import/core/base/task.lua12
-rw-r--r--xmake/modules/private/utils/complete.lua121
-rw-r--r--xmake/plugins/lua/xmake.lua6
8 files changed, 361 insertions, 97 deletions
diff --git a/scripts/get.ps1 b/scripts/get.ps1
index fc35a9023..4b186c23f 100644
--- a/scripts/get.ps1
+++ b/scripts/get.ps1
@@ -9,105 +9,166 @@ param (
& {
-Function myExit($code){
- if($code -is [int] -and $code -ne 0){
- throw $Error[0]
- }else{
- break
+ function myExit($code) {
+ if ($code -is [int] -and $code -ne 0) {
+ throw $Error[0]
+ } else {
+ break
+ }
}
-}
-Function writeErrorTip($msg){
- Write-Host $msg -BackgroundColor Red -ForegroundColor White
-}
+ function writeErrorTip($msg) {
+ Write-Host $msg -BackgroundColor Red -ForegroundColor White
+ }
-Function writeLogoLine($msg){
- Write-Host $msg -BackgroundColor White -ForegroundColor DarkBlue
-}
+ function writeLogoLine($msg) {
+ Write-Host $msg -BackgroundColor White -ForegroundColor DarkBlue
+ }
-writeLogoLine ' _ '
-writeLogoLine ' __ ___ __ __ __ _| | ______ '
-writeLogoLine ' \ \/ / | \/ |/ _ | |/ / __ \ '
-writeLogoLine ' > < | \__/ | /_| | < ___/ '
-writeLogoLine ' /_/\_\_|_| |_|\__ \|_|\_\____| getter '
-writeLogoLine ' '
-writeLogoLine ' '
+ function registerTabCompletion {
-if($PSVersionTable.PSVersion.Major -lt 5){
- writeErrorTip 'Sorry but PowerShell v5+ is required'
- throw 'PowerShell''s version too low'
-}
-$temppath=($env:TMP,$env:TEMP,'.' -ne $null)[0]
-$outfile=$temppath+"\$pid-xmake-installer.exe"
-try{
- Write-Output "$pid"|Out-File -FilePath "$outfile"
- Remove-Item "$outfile"
-}catch{
- writeErrorTip 'Cannot write to temp path'
- writeErrorTip 'Please set environment var "TMP" to another path'
- myExit 1
-}
-Write-Host "Start downloading https://github.com/xmake-io/xmake/releases/download/$version/xmake-$branch.exe .."
-try{
- [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
- Invoke-Webrequest "https://github.com/xmake-io/xmake/releases/download/$version/xmake-$branch.exe" -OutFile "$outfile"
-}catch{
- writeErrorTip 'Download failed!'
- writeErrorTip 'Check your network or... the news of S3 break'
- myExit 1
-}
-Write-Host 'Start installation... Hope your antivirus doesn''t trouble'
-$installdir=$HOME+'\xmake'
-Write-Host "Install to $installdir"
-try{
- Start-Process -FilePath "$outfile" -ArgumentList "/S /D=$installdir" -Wait
-}catch{
+ function writeDataToFile($file) {
+ $encoding = [text.encoding]::UTF8
+ if (Test-Path $file -PathType Leaf) {
+ #Create a stream reader to get the file's encoding and contents.
+ $sr = New-Object System.IO.StreamReader($file, $true)
+ [char[]] $buffer = new-object char[] 3
+ $sr.Read($buffer, 0, 3) | Out-Null
+ $encoding = $sr.CurrentEncoding
+ $sr.Close() | Out-Null
+
+ if ($(Get-Content $file) -imatch "Register-ArgumentCompleter -Native -CommandName xmake -ScriptBlock") {
+ Write-Host "Seems the tab completion of xmake has installed here..."
+ return
+ }
+ }
+
+ try {
+ [IO.File]::AppendAllText($file, "`n", $encoding)
+ } catch {
+ writeErrorTip "Failed to append to profile!"
+ writeErrorTip "Please try again as administrator"
+ return
+ }
+ try {
+ $content = (Invoke-Webrequest 'https://raw.githubusercontent.com/xmake-io/xmake/master/scripts/register-completions.ps1' -UseBasicParsing).Content
+ } catch {
+ writeErrorTip 'Download failed!'
+ writeErrorTip 'Check your network or... the news of S3 break'
+ return
+ }
+ [IO.File]::AppendAllText($file, $content, $encoding)
+ [IO.File]::AppendAllText($file, "`n", $encoding)
+ }
+ $message = 'Tab completion service'
+ $question = 'Would you like to install tab completion service of xmake to your profile?'
+
+ $choices = @(
+ (New-Object Management.Automation.Host.ChoiceDescription -ArgumentList @(
+ 'For &all users',
+ "Install for all users, writes to $($PROFILE.AllUsersAllHosts), admin privilege is needed.")),
+ (New-Object Management.Automation.Host.ChoiceDescription -ArgumentList @(
+ 'Just for &me',
+ "Install for current user, writes to $($PROFILE.CurrentUserAllHosts).")),
+ (New-Object Management.Automation.Host.ChoiceDescription -ArgumentList @(
+ 'Just for this &host',
+ "Install for current user current host, writes to $($PROFILE.CurrentUserCurrentHost).")),
+ (New-Object Management.Automation.Host.ChoiceDescription -ArgumentList @(
+ '&No',
+ "Do not install xmake's tab completion service."))
+ )
+ switch ($Host.UI.PromptForChoice($message, $question, $choices, 1)) {
+ 0 { writeDataToFile($PROFILE.AllUsersAllHosts) }
+ 1 { writeDataToFile($PROFILE.CurrentUserAllHosts) }
+ 2 { writeDataToFile($PROFILE.CurrentUserCurrentHost) }
+ }
+ }
+
+ writeLogoLine ' _ '
+ writeLogoLine ' __ ___ __ __ __ _| | ______ '
+ writeLogoLine ' \ \/ / | \/ |/ _ | |/ / __ \ '
+ writeLogoLine ' > < | \__/ | /_| | < ___/ '
+ writeLogoLine ' /_/\_\_|_| |_|\__ \|_|\_\____| getter '
+ writeLogoLine ' '
+ writeLogoLine ' '
+
+ if ($PSVersionTable.PSVersion.Major -lt 5) {
+ writeErrorTip 'Sorry but PowerShell v5+ is required'
+ throw 'PowerShell''s version too low'
+ }
+ $temppath = ($env:TMP, $env:TEMP, '.' -ne $null)[0]
+ $outfile = $temppath + "\$pid-xmake-installer.exe"
+ try {
+ Write-Output "$pid" | Out-File -FilePath "$outfile"
+ Remove-Item "$outfile"
+ } catch {
+ writeErrorTip 'Cannot write to temp path'
+ writeErrorTip 'Please set environment var "TMP" to another path'
+ myExit 1
+ }
+ Write-Host "Start downloading https://github.com/xmake-io/xmake/releases/download/$version/xmake-$branch.exe .."
+ try {
+ [Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
+ Invoke-Webrequest "https://github.com/xmake-io/xmake/releases/download/$version/xmake-$branch.exe" -OutFile "$outfile"
+ } catch {
+ writeErrorTip 'Download failed!'
+ writeErrorTip 'Check your network or... the news of S3 break'
+ myExit 1
+ }
+ Write-Host 'Start installation... Hope your antivirus doesn''t trouble'
+ $installdir = $HOME + '\xmake'
+ Write-Host "Install to $installdir"
+ try {
+ Start-Process -FilePath "$outfile" -ArgumentList "/S /D=$installdir" -Wait
+ } catch {
+ Remove-Item "$outfile"
+ writeErrorTip 'Install failed!'
+ writeErrorTip 'Close your antivirus then try again'
+ myExit 1
+ }
Remove-Item "$outfile"
- writeErrorTip 'Install failed!'
- writeErrorTip 'Close your antivirus then try again'
- myExit 1
-}
-Remove-Item "$outfile"
-Write-Host 'Adding to PATH... almost done'
-$env:Path+=";$installdir"
-[Environment]::SetEnvironmentVariable("Path",[Environment]::GetEnvironmentVariable("Path",[System.EnvironmentVariableTarget]::User)+";$installdir",[System.EnvironmentVariableTarget]::User) # this step is optional because installer writes path to regedit
-try{
- xmake --version
-}catch{
- writeErrorTip 'Everything is showing installation has finished'
- writeErrorTip 'But xmake could not run... Why?'
- myExit 1
-}
-Write-Host "Pulling xmake from branch $branch"
-$outfile=$temppath+"\$pid-xmake-repo.zip"
-try{
- Invoke-Webrequest "https://github.com/xmake-io/xmake/archive/$branch.zip" -OutFile "$outfile"
-}catch{
- writeErrorTip 'Pull Failed!'
- writeErrorTip 'xmake is now available but may not be newest'
- myExit
-}
-Write-Host 'Expanding archive...'
-New-Item -Path "$temppath" -Name "$pid-xmake-repo" -ItemType "directory" -Force
-$oldpwd=$pwd
-$repodir=$temppath+"\$pid-xmake-repo"
-try{
- Expand-Archive "$outfile" "$repodir" -Force
- Write-Host 'Self-building...'
- Set-Location ($repodir+"\xmake-$branch\core")
- xmake
- Write-Host 'Copying new files...'
- Copy-Item 'build\xmake.exe' "$installdir" -Force
- Set-Location '..\xmake'
- Copy-Item * "$installdir" -Recurse -Force
- xmake --version
-}catch{
- writeErrorTip 'Update Failed!'
- writeErrorTip 'xmake is now available but may not be newest'
-}finally{
- Set-Location "$oldpwd" -ErrorAction SilentlyContinue
- Remove-Item "$outfile" -ErrorAction SilentlyContinue
- Remove-Item "$repodir" -Recurse -Force -ErrorAction SilentlyContinue
-}
+ Write-Host 'Adding to PATH... almost done'
+ $env:Path += ";$installdir"
+ [Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User) + ";$installdir", [System.EnvironmentVariableTarget]::User) # this step is optional because installer writes path to regedit
+ try {
+ xmake --version
+ } catch {
+ writeErrorTip 'Everything is showing installation has finished'
+ writeErrorTip 'But xmake could not run... Why?'
+ myExit 1
+ }
+ Write-Host "Pulling xmake from branch $branch"
+ $outfile = $temppath + "\$pid-xmake-repo.zip"
+ try {
+ Invoke-Webrequest "https://github.com/xmake-io/xmake/archive/$branch.zip" -OutFile "$outfile"
+ } catch {
+ writeErrorTip 'Pull Failed!'
+ writeErrorTip 'xmake is now available but may not be newest'
+ myExit
+ }
+ Write-Host 'Expanding archive...'
+ New-Item -Path "$temppath" -Name "$pid-xmake-repo" -ItemType "directory" -Force
+ $oldpwd = $pwd
+ $repodir = $temppath + "\$pid-xmake-repo"
+ try {
+ Expand-Archive "$outfile" "$repodir" -Force
+ Write-Host 'Self-building...'
+ Set-Location ($repodir + "\xmake-$branch\core")
+ xmake
+ Write-Host 'Copying new files...'
+ Copy-Item 'build\xmake.exe' "$installdir" -Force
+ Set-Location '..\xmake'
+ Copy-Item * "$installdir" -Recurse -Force
+ xmake --version
+ } catch {
+ writeErrorTip 'Update Failed!'
+ writeErrorTip 'xmake is now available but may not be newest'
+ } finally {
+ Set-Location "$oldpwd" -ErrorAction SilentlyContinue
+ Remove-Item "$outfile" -ErrorAction SilentlyContinue
+ Remove-Item "$repodir" -Recurse -Force -ErrorAction SilentlyContinue
+ }
+
+ registerTabCompletion
}
diff --git a/scripts/get.sh b/scripts/get.sh
index 98a59ec2a..164ec9c48 100755
--- a/scripts/get.sh
+++ b/scripts/get.sh
@@ -147,6 +147,42 @@ install_profile()
{
if [ ! -d ~/.xmake ]; then mkdir ~/.xmake; fi
echo "export PATH=$prefix/bin:\$PATH" > ~/.xmake/profile
+ echo '
+if [[ "$SHELL" = */zsh ]]; then
+
+ # zsh parameter completion for xmake
+
+ _xmake_zsh_complete()
+ {
+ local completions=("$(xmake lua private.utils.complete 0 "$words")")
+
+ reply=( "${(ps:\n:)completions}" )
+ }
+
+ compctl -K _xmake_zsh_complete xmake
+
+elif [[ "$SHELL" = */bash ]]; then
+
+# bash parameter completion for xmake
+
+ _xmake_bash_complete()
+ {
+ local word=${COMP_WORDS[COMP_CWORD]}
+
+ local completions
+ completions="$(xmake lua private.utils.complete "${COMP_POINT}" "${COMP_LINE}" 2>/dev/null)"
+ if [ $? -ne 0 ]; then
+ completions=""
+ fi
+
+ COMPREPLY=( $(compgen -W "$completions" -- "$word") )
+ }
+
+ complete -f -F _xmake_bash_complete xmake
+
+fi
+' >> ~/.xmake/profile
+
if [[ "$SHELL" = */zsh ]]; then write_profile ~/.zshrc
elif [[ "$SHELL" = */ksh ]]; then write_profile ~/.kshrc
elif [[ "$SHELL" = */bash ]]; then write_profile ~/.bashrc
diff --git a/scripts/register-completions.bash b/scripts/register-completions.bash
new file mode 100644
index 000000000..11cadedf3
--- /dev/null
+++ b/scripts/register-completions.bash
@@ -0,0 +1,16 @@
+# bash parameter completion for xmake
+
+_xmake_bash_complete()
+{
+ local word=${COMP_WORDS[COMP_CWORD]}
+
+ local completions
+ completions="$(xmake lua private.utils.complete "${COMP_POINT}" "${COMP_LINE}" 2>/dev/null)"
+ if [ $? -ne 0 ]; then
+ completions=""
+ fi
+
+ COMPREPLY=( $(compgen -W "$completions" -- "$word") )
+}
+
+complete -f -F _xmake_bash_complete xmake
diff --git a/scripts/register-completions.ps1 b/scripts/register-completions.ps1
new file mode 100644
index 000000000..58e11320a
--- /dev/null
+++ b/scripts/register-completions.ps1
@@ -0,0 +1,8 @@
+# PowerShell parameter completion shim for xmake
+
+Register-ArgumentCompleter -Native -CommandName xmake -ScriptBlock {
+ param($commandName, $wordToComplete, $cursorPosition)
+ xmake lua private.utils.complete "$cursorPosition" "$wordToComplete" | ForEach-Object {
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
+ }
+}
diff --git a/scripts/register-completions.zsh b/scripts/register-completions.zsh
new file mode 100644
index 000000000..ff019569f
--- /dev/null
+++ b/scripts/register-completions.zsh
@@ -0,0 +1,10 @@
+# zsh parameter completion for xmake
+
+_xmake_zsh_complete()
+{
+ local completions=("$(xmake lua private.utils.complete 0 "$words")")
+
+ reply=( "${(ps:\n:)completions}" )
+}
+
+compctl -K _xmake_zsh_complete xmake
diff --git a/xmake/core/sandbox/modules/import/core/base/task.lua b/xmake/core/sandbox/modules/import/core/base/task.lua
index d6cdcef01..1d322b494 100644
--- a/xmake/core/sandbox/modules/import/core/base/task.lua
+++ b/xmake/core/sandbox/modules/import/core/base/task.lua
@@ -54,7 +54,7 @@ function sandbox_core_base_task.run(taskname, options, ...)
-- get task instance
local taskname = option.taskname() or "build"
- local taskinst = project.task(taskname) or task.task(taskname)
+ local taskinst = project.task(taskname) or task.task(taskname)
if not taskinst then
raise("do unknown task(%s)!", taskname)
end
@@ -69,5 +69,15 @@ function sandbox_core_base_task.run(taskname, options, ...)
option.restore()
end
+
+function sandbox_core_base_task.tasks()
+ local tasks = {}
+ for k, _ in pairs(task.tasks()) do
+ local menu = option.taskmenu(k)
+ tasks[k] = menu
+ end
+ return task.tasks()
+end
+
-- return module
return sandbox_core_base_task
diff --git a/xmake/modules/private/utils/complete.lua b/xmake/modules/private/utils/complete.lua
new file mode 100644
index 000000000..5c85482fb
--- /dev/null
+++ b/xmake/modules/private/utils/complete.lua
@@ -0,0 +1,121 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2019, TBOOX Open Source Group.
+--
+-- @author OpportunityLiu
+-- @file complete.lua
+--
+
+-- imports
+import("core.base.option")
+import("core.base.task")
+
+local tasks = task.tasks()
+local shortnames = {}
+for k, v in pairs(tasks) do
+ if v.shortname then
+ shortnames[menu.shortname] = k
+ end
+end
+
+function _print_candidate(...)
+ local candidate = format(...)
+ if candidate and #candidate ~= 0 then
+ print(candidate)
+ end
+end
+
+function _complete_task(name)
+ local has_candidate = false
+ for k, _ in pairs(tasks) do
+ if k:startswith(name) then
+ _print_candidate(k)
+ has_candidate = true
+ end
+ end
+ for k, _ in pairs(tasks) do
+ -- not startswith
+ if k:find(name, 2, true) then
+ _print_candidate(k)
+ has_candidate = true
+ end
+ end
+ return has_candidate
+end
+
+function _complete_option(options, name)
+ local state = 0
+ if name == "-" or name == "--" then
+ name = ""
+ elseif name:startswith("--") then
+ state = 2
+ name = name:sub(3)
+ elseif name:startswith("-") then
+ state = 1
+ name = name:sub(2)
+ end
+
+ -- search full names only
+ if name == "" then state = 2 end
+
+ local opcandi = {}
+ for _, v in ipairs(options) do
+ if v[3] == "kv" or v[3] == "k" then table.insert(opcandi, v) end
+ end
+
+ for _, v in ipairs(opcandi) do
+ if (state == 2 or state == 0) and v[2]:startswith(name) then
+ _print_candidate((v[3] == "k") and "--%s" or "--%s=", v[2])
+ elseif (state == 1 or state == 0) and v[1] and v[1]:startswith(name) then
+ _print_candidate((v[3] == "k") and "-%s" or "-%s ", v[1])
+ end
+ end
+ for _, v in ipairs(opcandi) do
+ -- not startswith
+ if (state == 2 or state == 0) and v[2]:find(name, 2, true) then
+ _print_candidate((v[3] == "k") and "--%s" or "--%s=", v[2])
+ elseif (state == 1 or state == 0) and v[1] and v[1]:find(name, 2, true) then
+ _print_candidate((v[3] == "k") and "-%s" or "-%s ", v[1])
+ end
+ end
+end
+
+function main(position, ...)
+ word = table.concat({...}, " ") or ""
+ position = tonumber(position) or 0
+ if position > #word then
+ word = word .. " "
+ end
+ if word:lower():startswith("xmake ") then
+ word = word:sub(#"xmake " + 1)
+ end
+ if word:lower() == "xmake" then
+ return _complete_task("")
+ end
+
+ local segs = word:split("%s")
+ local task = table.remove(segs, 1) or ""
+ if #segs == 0 and not word:endswith(" ") then
+ if _complete_task(task) then return end
+ end
+
+ if shortnames[task] then task = shortnames[task] end
+ if not tasks[task] then
+ table.insert(segs, 1, task)
+ task = "run"
+ end
+ _complete_option(option.taskmenu(task).options, word:endswith(" ") and "" or segs[#segs])
+ return
+end \ No newline at end of file
diff --git a/xmake/plugins/lua/xmake.lua b/xmake/plugins/lua/xmake.lua
index 636ef67b8..11fce7a20 100644
--- a/xmake/plugins/lua/xmake.lua
+++ b/xmake/plugins/lua/xmake.lua
@@ -73,13 +73,15 @@ task("lua")
break
end
end
+ local result = nil
if object then
-- run builtin modules (xmake lua core.xxx.xxx)
- print(object(unpack(option.get("arguments") or {})))
+ result = object(unpack(option.get("arguments") or {}))
else
-- run imported modules (xmake lua core.xxx.xxx)
- print(import(script, {anonymous = true})(unpack(option.get("arguments") or {})))
+ result = import(script, {anonymous = true})(unpack(option.get("arguments") or {}))
end
+ if result ~= nil then print(result) end
end
else
-- enter interactive mode