Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
掘金者说
vscode
提交
46101daf
V
vscode
项目概览
掘金者说
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
46101daf
编写于
2月 19, 2018
作者:
I
Isidor Nikolic
提交者:
GitHub
2月 19, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #43659 from Microsoft/foldersFromPath
Folders from path
上级
cac52572
10be0f69
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
165 addition
and
9 deletion
+165
-9
src/vs/base/browser/ui/inputbox/inputBox.css
src/vs/base/browser/ui/inputbox/inputBox.css
+1
-0
src/vs/workbench/parts/files/electron-browser/fileActions.ts
src/vs/workbench/parts/files/electron-browser/fileActions.ts
+37
-6
src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
...ench/parts/files/electron-browser/views/explorerViewer.ts
+21
-1
src/vs/workbench/parts/files/test/electron-browser/explorerModel.test.ts
...h/parts/files/test/electron-browser/explorerModel.test.ts
+6
-2
src/vs/workbench/services/files/test/node/fileService.test.ts
...vs/workbench/services/files/test/node/fileService.test.ts
+100
-0
未找到文件。
src/vs/base/browser/ui/inputbox/inputBox.css
浏览文件 @
46101daf
...
...
@@ -99,6 +99,7 @@
line-height
:
17px
;
min-height
:
34px
;
margin-top
:
-1px
;
word-wrap
:
break-word
;
}
/* Action bar support */
...
...
src/vs/workbench/parts/files/electron-browser/fileActions.ts
浏览文件 @
46101daf
...
...
@@ -1325,6 +1325,7 @@ export class CopyPathAction extends Action {
}
}
export
function
validateFileName
(
parent
:
IFileStat
,
name
:
string
,
allowOverwriting
:
boolean
=
false
):
string
{
// Produce a well formed file name
...
...
@@ -1335,21 +1336,29 @@ export function validateFileName(parent: IFileStat, name: string, allowOverwriti
return
nls
.
localize
(
'
emptyFileNameError
'
,
"
A file or folder name must be provided.
"
);
}
const
names
:
string
[]
=
name
.
split
(
/
[\\/]
/
).
filter
(
part
=>
!!
part
);
// Do not allow to overwrite existing file
if
(
!
allowOverwriting
)
{
if
(
parent
.
children
&&
parent
.
children
.
some
((
c
)
=>
{
if
(
isLinux
)
{
return
c
.
name
===
name
;
let
p
=
parent
;
const
alreadyExisting
=
names
.
every
((
folderName
)
=>
{
let
{
exists
,
child
}
=
alreadyExists
(
p
,
folderName
);
if
(
!
exists
)
{
return
false
;
}
else
{
p
=
child
;
return
true
;
}
});
return
c
.
name
.
toLowerCase
()
===
name
.
toLowerCase
();
}))
{
if
(
alreadyExisting
)
{
return
nls
.
localize
(
'
fileNameExistsError
'
,
"
A file or folder **{0}** already exists at this location. Please choose a different name.
"
,
name
);
}
}
// Invalid File name
if
(
!
paths
.
isValidBasename
(
name
))
{
if
(
names
.
some
((
folderName
)
=>
!
paths
.
isValidBasename
(
folderName
)
))
{
return
nls
.
localize
(
'
invalidFileNameError
'
,
"
The name **{0}** is not valid as a file or folder name. Please choose a different name.
"
,
trimLongName
(
name
));
}
...
...
@@ -1364,6 +1373,28 @@ export function validateFileName(parent: IFileStat, name: string, allowOverwriti
return
null
;
}
function
alreadyExists
(
parent
:
IFileStat
,
name
:
string
):
{
exists
:
boolean
,
child
:
IFileStat
|
undefined
}
{
let
duplicateChild
:
IFileStat
;
if
(
parent
.
children
)
{
let
exists
:
boolean
=
parent
.
children
.
some
((
c
)
=>
{
let
found
:
boolean
;
if
(
isLinux
)
{
found
=
c
.
name
===
name
;
}
else
{
found
=
c
.
name
.
toLowerCase
()
===
name
.
toLowerCase
();
}
if
(
found
)
{
duplicateChild
=
c
;
}
return
found
;
});
return
{
exists
,
child
:
duplicateChild
};
}
return
{
exists
:
false
,
child
:
undefined
};
}
function
trimLongName
(
name
:
string
):
string
{
if
(
name
&&
name
.
length
>
255
)
{
return
`
${
name
.
substr
(
0
,
255
)}
...`
;
...
...
src/vs/workbench/parts/files/electron-browser/views/explorerViewer.ts
浏览文件 @
46101daf
...
...
@@ -16,7 +16,7 @@ import resources = require('vs/base/common/resources');
import
errors
=
require
(
'
vs/base/common/errors
'
);
import
{
IAction
,
ActionRunner
as
BaseActionRunner
,
IActionRunner
}
from
'
vs/base/common/actions
'
;
import
comparers
=
require
(
'
vs/base/common/comparers
'
);
import
{
InputBox
}
from
'
vs/base/browser/ui/inputbox/inputBox
'
;
import
{
InputBox
,
MessageType
}
from
'
vs/base/browser/ui/inputbox/inputBox
'
;
import
{
isMacintosh
,
isLinux
}
from
'
vs/base/common/platform
'
;
import
glob
=
require
(
'
vs/base/common/glob
'
);
import
{
FileLabel
,
IFileLabelOptions
}
from
'
vs/workbench/browser/labels
'
;
...
...
@@ -308,6 +308,10 @@ export class FileRenderer implements IRenderer {
done
(
false
,
false
);
}
}),
DOM
.
addStandardDisposableListener
(
inputBox
.
inputElement
,
DOM
.
EventType
.
KEY_UP
,
(
e
:
IKeyboardEvent
)
=>
{
const
initialRelPath
:
string
=
relative
(
stat
.
root
.
resource
.
fsPath
,
stat
.
parent
.
resource
.
fsPath
);
this
.
displayCurrentPath
(
inputBox
,
initialRelPath
,
fileKind
);
}),
DOM
.
addDisposableListener
(
inputBox
.
inputElement
,
DOM
.
EventType
.
BLUR
,
()
=>
{
done
(
inputBox
.
isInputValid
(),
true
);
}),
...
...
@@ -315,6 +319,22 @@ export class FileRenderer implements IRenderer {
styler
];
}
private
displayCurrentPath
(
inputBox
:
InputBox
,
initialRelPath
:
string
,
fileKind
:
FileKind
)
{
if
(
inputBox
.
validate
())
{
const
value
=
inputBox
.
value
;
if
(
value
&&
value
.
search
(
/
[\\/]
/
)
!==
-
1
)
{
// only show if there's a slash
const
newPath
=
paths
.
normalize
(
paths
.
join
(
initialRelPath
,
value
),
true
);
const
fileType
:
string
=
FileKind
[
fileKind
].
toLowerCase
();
inputBox
.
showMessage
({
type
:
MessageType
.
INFO
,
content
:
nls
.
localize
(
'
constructedPath
'
,
"
Create {0} in **{1}**
"
,
fileType
,
newPath
),
formatContent
:
true
});
}
}
}
}
// Explorer Accessibility Provider
...
...
src/vs/workbench/parts/files/test/electron-browser/explorerModel.test.ts
浏览文件 @
46101daf
...
...
@@ -194,8 +194,12 @@ suite('Files - View Model', () => {
assert
(
validateFileName
(
s
,
''
)
!==
null
);
assert
(
validateFileName
(
s
,
'
'
)
!==
null
);
assert
(
validateFileName
(
s
,
'
Read Me
'
)
===
null
,
'
name containing space
'
);
assert
(
validateFileName
(
s
,
'
foo/bar
'
)
!==
null
);
assert
(
validateFileName
(
s
,
'
foo
\\
bar
'
)
!==
null
);
assert
(
validateFileName
(
s
,
'
foo/bar
'
)
===
null
);
assert
(
validateFileName
(
s
,
'
foo
\\
bar
'
)
===
null
);
assert
(
validateFileName
(
s
,
'
all/slashes/are/same
'
)
===
null
);
assert
(
validateFileName
(
s
,
'
theres/one/different
\\
slash
'
)
===
null
);
assert
(
validateFileName
(
s
,
'
/slashAtBeginning
'
)
===
null
);
if
(
isWindows
)
{
assert
(
validateFileName
(
s
,
'
foo:bar
'
)
!==
null
);
assert
(
validateFileName
(
s
,
'
foo*bar
'
)
!==
null
);
...
...
src/vs/workbench/services/files/test/node/fileService.test.ts
浏览文件 @
46101daf
...
...
@@ -136,6 +136,33 @@ suite('FileService', () => {
},
error
=>
onError
(
error
,
done
));
});
test
(
'
createFolder: creating multiple folders at once
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
event
=
e
;
});
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
service
.
resolveFile
(
uri
.
file
(
testDir
)).
done
(
parent
=>
{
const
resource
=
uri
.
file
(
path
.
join
(
parent
.
resource
.
fsPath
,
...
multiFolderPaths
));
return
service
.
createFolder
(
resource
).
then
(
f
=>
{
const
lastFolderName
=
multiFolderPaths
[
multiFolderPaths
.
length
-
1
];
assert
.
equal
(
f
.
name
,
lastFolderName
);
assert
.
equal
(
fs
.
existsSync
(
f
.
resource
.
fsPath
),
true
);
assert
.
ok
(
event
);
assert
.
equal
(
event
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
operation
,
FileOperation
.
CREATE
);
assert
.
equal
(
event
.
target
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
target
.
isDirectory
,
true
);
toDispose
.
dispose
();
done
();
});
},
error
=>
onError
(
error
,
done
));
});
test
(
'
touchFile
'
,
function
(
done
:
()
=>
void
)
{
service
.
touchFile
(
uri
.
file
(
path
.
join
(
testDir
,
'
test.txt
'
))).
done
(
s
=>
{
assert
.
equal
(
s
.
name
,
'
test.txt
'
);
...
...
@@ -156,6 +183,28 @@ suite('FileService', () => {
},
error
=>
onError
(
error
,
done
));
});
test
(
'
touchFile - multi folder
'
,
function
(
done
:
()
=>
void
)
{
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
service
.
touchFile
(
uri
.
file
(
path
.
join
(
testDir
,
...
multiFolderPaths
,
'
test.txt
'
))).
done
(
s
=>
{
assert
.
equal
(
s
.
name
,
'
test.txt
'
);
assert
.
equal
(
fs
.
existsSync
(
s
.
resource
.
fsPath
),
true
);
assert
.
equal
(
fs
.
readFileSync
(
s
.
resource
.
fsPath
).
length
,
0
);
const
stat
=
fs
.
statSync
(
s
.
resource
.
fsPath
);
return
TPromise
.
timeout
(
10
).
then
(()
=>
{
return
service
.
touchFile
(
s
.
resource
).
done
(
s
=>
{
const
statNow
=
fs
.
statSync
(
s
.
resource
.
fsPath
);
assert
.
ok
(
statNow
.
mtime
.
getTime
()
>=
stat
.
mtime
.
getTime
());
// one some OS the resolution seems to be 1s, so we use >= here
assert
.
equal
(
statNow
.
size
,
stat
.
size
);
done
();
});
});
},
error
=>
onError
(
error
,
done
));
});
test
(
'
renameFile
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
...
...
@@ -179,6 +228,32 @@ suite('FileService', () => {
},
error
=>
onError
(
error
,
done
));
});
test
(
'
renameFile - multi folder
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
event
=
e
;
});
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
const
renameToPath
=
path
.
join
(...
multiFolderPaths
,
'
other.html
'
);
const
resource
=
uri
.
file
(
path
.
join
(
testDir
,
'
index.html
'
));
service
.
resolveFile
(
resource
).
done
(
source
=>
{
return
service
.
rename
(
source
.
resource
,
renameToPath
).
then
(
renamed
=>
{
assert
.
equal
(
fs
.
existsSync
(
renamed
.
resource
.
fsPath
),
true
);
assert
.
equal
(
fs
.
existsSync
(
source
.
resource
.
fsPath
),
false
);
assert
.
ok
(
event
);
assert
.
equal
(
event
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
operation
,
FileOperation
.
MOVE
);
assert
.
equal
(
event
.
target
.
resource
.
fsPath
,
renamed
.
resource
.
fsPath
);
toDispose
.
dispose
();
done
();
});
},
error
=>
onError
(
error
,
done
));
});
test
(
'
renameFolder
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
...
...
@@ -202,6 +277,31 @@ suite('FileService', () => {
});
});
test
(
'
renameFolder - multi folder
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
event
=
e
;
});
const
multiFolderPaths
=
[
'
a
'
,
'
couple
'
,
'
of
'
,
'
folders
'
];
const
renameToPath
=
path
.
join
(...
multiFolderPaths
);
const
resource
=
uri
.
file
(
path
.
join
(
testDir
,
'
deep
'
));
service
.
resolveFile
(
resource
).
done
(
source
=>
{
return
service
.
rename
(
source
.
resource
,
renameToPath
).
then
(
renamed
=>
{
assert
.
equal
(
fs
.
existsSync
(
renamed
.
resource
.
fsPath
),
true
);
assert
.
equal
(
fs
.
existsSync
(
source
.
resource
.
fsPath
),
false
);
assert
.
ok
(
event
);
assert
.
equal
(
event
.
resource
.
fsPath
,
resource
.
fsPath
);
assert
.
equal
(
event
.
operation
,
FileOperation
.
MOVE
);
assert
.
equal
(
event
.
target
.
resource
.
fsPath
,
renamed
.
resource
.
fsPath
);
toDispose
.
dispose
();
done
();
});
});
});
test
(
'
renameFile - MIX CASE
'
,
function
(
done
:
()
=>
void
)
{
let
event
:
FileOperationEvent
;
const
toDispose
=
service
.
onAfterOperation
(
e
=>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录