如何有效地在Vim中处理多个文件


1098

我已经开始使用Vim开发Perl脚本,并且开始发现它非常强大。

我喜欢的一件事是能够使用以下方法一次打开多个文件:

vi main.pl maintenance.pl

然后在它们之间跳:

:n
:prev

并查看打开哪个文件:

:args

要添加文件,我可以说:

:n test.pl

我希望将其添加到我的文件列表中,但是它将清除当前的文件列表,并且在我键入时:args我只能test.pl打开。

那么,如何在args列表中添加和删除文件?


5
tmux ...在每个窗格中使用vim
Tommy 2016年

4
@Tommy:这样,您就无法在文件之间(vims缓冲区)粘贴被选中/删除的内容。如果有的话,只有剪贴板可能会有所帮助(请参阅公认的答案:stackoverflow.com/questions/5532878/…
ChristophS,

1
:N似乎是前往上一个文件的简便方法...
Gert van den Berg

vimcasts.org/categories/the-argument-list?在学习vim时,强烈建议使用VimCast。
mcepl

Answers:


1171

为什么不使用选项卡(在Vim 7中引入)?您可以在标签之间切换用:tabn:tabp,有了:tabe <filepath>您可以添加新的选项卡; 并使用常规:q:wq关闭标签页。如果映射:tabn:tabp你的F7/ F8键,您可以文件之间轻松切换。

如果没有那么多文件,或者您没有Vim 7,也可以将屏幕拆分为多个文件::sp <filepath>。然后,您可以使用Ctrl+ W,然后按您要移动的方向(或代替箭头键,w用于下一个和W上一个拆分屏幕)在拆分屏幕之间切换。


72
要保存和关闭标签页,您也可以使用ZZ代替:wq(就像通常保存并关闭标签一样)
Andreas Grech 2010年

40
我正在Ubuntu 10.10中使用vim-gnome软件包,并且可以使用Ctrl + PageUp和Ctrl + PageDown在选项卡之间切换。我不需要配置任何东西。这是默认设置。
乔伊·亚当斯

268
同样,在编辑模式下,gt转到下一个选项卡,然后gT转到上一个选项卡。
院长

40
您可以使用ngt跳到任何选项卡,其中n是选项卡的索引(从1开始)。我认为有一个选项可以在文件名附近显示每个选项卡的索引,但是我不知道它是什么。如果有人知道,我很想听听。
void-pointer

81
还要注意,您可以使用该-p标志从命令行在选项卡中打开多个文件。例如,gvim -p main.pl maintenance.pl将在选项卡中打开这两个文件。
马修·斯特劳布里奇

554

清单

要查看当前缓冲区的列表,我使用:

:ls

开场

要打开一个新文件,我使用

:e ../myFile.pl

具有增强的制表符完成功能(set wildmenu输入.vimrc)。

注意:您也可以使用:find来为您搜索一组路径,但是您需要首先自定义这些路径。


交换

要在所有打开的文件之间切换,我使用

:b myfile

具有增强的制表符完成功能(仍然set wildmenu)。

注意::b#选择上次访问的文件,因此您可以使用它在两个文件之间快速切换。


使用视窗

Ctrl-W sCtrl-W v水平和垂直拆分当前窗口。您也可以使用:split:vertical split:sp:vs

Ctrl-W w在打开的窗口之间切换,和Ctrl-W h(或jkl)在打开的窗口中导航。

Ctrl-W c 关闭当前窗口,以及 Ctrl-W o关闭除当前窗口以外的所有窗口。

-o-O标志开头的vim会以各自的拆分方式打开每个文件。


有了这些,我不需要Vim中的选项卡,而且手指可以找到缓冲区,而不是眼睛。

注意:如果您希望所有文件都进入Vim的同一实例,请使用--remote-silent选项启动Vim 。


4
如果您正在使用多个缓冲区,我建议使用LustyJuggler
阿伦M 2010年

1
感谢您为处理多个文件时最常用的vim命令提供了非常好的快速参考。
2011年

9
:b这是一个非常强大的命令,因为它可以接受缓冲区编号和缓冲区名称作为参数。还有什么?它还支持文件名任何部分的制表符补全。假设您在缓冲区2中打开了foo.txt,可以键入:b 2<Enter>:b foo.txt:b oo<Tab><Enter>编辑该文件。是的,当您按下<Tab>时,最后一个将完成对“ foo.txt”的“ oo”。
苏珊·帕尔

21
我的.vimrc:中有这一行nnoremap gb :ls<cr>:b<space>。当我gb在命令模式下键入时,它将列出我打开的缓冲区和类型:b ,以供我开始输入缓冲区名称/编号。
nkorth,2015年

5
还值得一提的是:b,只要它是明确的,它将接受子字符串匹配。因此,如果您打开了文件foobarbaz,就:b z足以将您切换到baz缓冲区,:b oo或者:b o将您带到foo缓冲区。
索伦·比约斯塔德

233
:ls

有关打开缓冲区的列表

  • :bp 前一个缓冲区
  • :bn 下一个缓冲区
  • :bnn一个数字)移到第n个缓冲区
  • :b <filename-part> 使用Tab键提供自动完成功能(太棒了!)

在某些版本的vim中,bnbp分别是bnextbprevious。标签自动完成在这种情况下很有用。

或者,当您处于普通模式时,可使用^切换到上一个正在处理的文件。

另外,您可以保存vim的会话

:mksession! ~/today.ses

上面的命令将当前打开的文件缓冲区和设置保存到~/today.ses。您可以使用加载该会话

vim -S ~/today.ses

不用麻烦记住您昨天离开的地方。;)


转到特定缓冲区:N CTRL- ^
Tom Yang

8
@shyam我想我爱你!我以某种方式永远不确定mksession命令,但是今天我突然想到,必须有某种方法来保存文件列表以轻松打开它们。这甚至更好,因为它似乎可以存储事物的完整状态(窗口拆分,缓冲区位置等)。那谢谢啦!
卡萨波

另外,使用"标记跳到上次在文件中的位置。

113

要添加到args列表中:

:argadd

要从args列表中删除:

:argdelete

在您的示例中,您可以使用:argedittest.pl将test.pl添加到args列表中并一步编辑文件。

:help args 提供更多细节和高级用法


4
这确实是所提问题的答案,尽管给出的标题其他答案也很合理。
Soren Bjornstad '16

48

我使用缓冲区命令- :bn(下一个缓冲区),:bp(上一个缓冲区):buffers(列出打开的缓冲区):b<n>(打开的缓冲区n):bd(删除缓冲区)。:e <filename>只会打开一个新的缓冲区。


18
:ls比:buffers更快
aehlke 2010年

42

我认为您可能使用了错误的命令来查看已打开的文件列表。

尝试做一个,:ls以查看已打开的文件列表,您将看到:

   1 %a   "./checkin.pl"            line 1
  2 #    "./grabakamailogs.pl"     line 1
  3      "./grabwmlogs.pl"         line 0
  etc.

然后,您可以通过列出的数字来引用文件,例如:3b

或者您可以通过输入数字来拆分屏幕,但使用sb而不是b。

顺便说一句,%是指当前可见的文件,而#是指备用文件。

您可以通过按轻松在这两个文件之间切换 Ctrl Shift 6

编辑:就像:ls您可以:reg用来查看寄存器的当前内容,包括包含已删除内容的0-9寄存器。如果您想重复使用以前删除的某些文本,这尤其有用。


2
很高兴看到%和#等相关信息。+1
Ashish

35

Vim(但不是原始的Vi!)有一些选项卡,我发现(在许多情况下)这些选项卡比缓冲区更好。您可以说:tabe [filename]要在新标签页中打开文件。通过单击选项卡或组合键[ n ] gt和可以完成选项卡之间的循环gT。图形Vim甚至具有图形选项卡。


1
谢谢,听起来不错,但很遗憾,我们仅在服务器上安装了VIM 6.1。
爱德华·坦格

1
带通配符的制表符非常方便:vim -p dir/*。选项卡的最大大小为10,但是您可以在~/.vimrc设置中将其更改tabpagemax为其他值。
Campa 2013年

27

这里有很多答案!我不用重新设计轮子就能使用的东西-最著名的插件(不会很快消失并且被很多人使用)超级快且令人讨厌。

  • ctrlpvim / ctrlp.vim-按名称查找文件,按位置或名称模糊搜索
  • jlanzarotta / bufexplorer-浏览打开的缓冲区(当您不记得最近打开和修改过多少文件并且不记得它们在哪里时,可能是因为您使用Ag搜索了它们)
  • rking / ag.vim搜索有关gitignore的文件
  • scrooloose / nerdtree查看目录结构,环顾四周,添加/删除/修改文件

编辑:最近我一直在使用dyng / ctrlsf.vim 进行上下文视图搜索(例如Sublime搜索),并且我将引擎从ag切换到ripgrep。表现出色。

EDIT2:CtrlSF一起,您可以使用mg979 / vim-visual-multi,一次对多个文件进行更改,然后最后一次保存它们。


2
ctrlp已移动,现在位于ctrlpvim / ctrlp.vim
Dave,

1
这是正确的答案!为什么没有更多投票?
ThomasMöbius16年

2
它没有更多支持,因为这个问题是在2008年提出的。:)
burnettk

究竟。我无法想象没有这些插件的开发环境中的vim。
Edgar Alloro

25

:e并且:badd只会接受一个参数的事情,因此以下操作将失败

:e foo.txt bar.txt
:e /foo/bar/*.txt
:badd /foo/bar/*

如果要从vim中添加多个文件,请使用 arga[dd]

:arga foo.txt bar.txt
:arga /foo/bar/*.txt
:argadd /foo/bar/*

21

该线程中的某些答案建议使用制表符,而其他建议使用缓冲区来完成相同的事情。制表符和缓冲区是不同的。我强烈建议您阅读本文“ Vim Tab疯狂-缓冲区与Tabs ”。

这是我从文章中摘录的一个不错的摘要:

摘要:

  • 缓冲区是文件的内存中文本。
  • 窗口是缓冲区上的视口。
  • 标签页是窗口的集合。

2
您可以通过输入:help windowVim 来获得摘要
icc97 '19

19

在vim中使用多个文件时,我主要使用以下命令(打开约350个文件):

  • :b <partial filename><tab> (跳到缓冲区)
  • :bw (擦除缓冲区,删除缓冲区)
  • :e <file path> (编辑,打开一个新的缓冲区>
  • pltags -允许跳转到子程序/方法定义

2
350个文件!令人印象深刻。您如何找到要跳转的正确缓冲区?你曾经做过分裂吗?
Brian O'Dell 2014年

3
@ BrianO'Dell的:b <partial filename><tab>set wildmenu在你的.vimrc作品好,因为当你已经有了吨开放缓冲区。然后,您只进行部分匹配并滚动找到它。在其他不错的编辑器中,您会发现模糊的内容,但通常不能将模糊的内容限制为仅打开的文件。
icc97'9

17

添加其他答案,因为任何答案均未涵盖

更改所有缓冲区以进行tab查看。

 :tab sball

将打开所有缓冲区到选项卡视图。然后我们可以使用任何与制表符相关的命令

gt or :tabn           "    go to next tab
gT or :tabp or :tabN  "    go to previous tab

的详细信息:help tab-page-commands

我们可以指示vim通过标签打开多个文件(作为选项卡视图)vim -p file1 file2alias vim='vim -p'将很有用。
同样的事情也可以通过以下命令来实现:~/.vimrc

 au VimEnter * if !&diff | tab all | tabfirst | endif

无论如何回答这个问题:要添加到arg列表中arga file,,

要从arg列表中删除: argd pattern

更多内容 :help arglist


16

您可能需要使用Vim全局标记

这样,您可以快速在文件之间跳动,甚至跳到文件中标记的位置。而且,关键命令很简短: 'C 将我带到正在使用的代码,'T 将我带到正在使用 的单元测试。

当您更改位置时,重置标记也很快: mC 标记新的代码点, mT 标记新的测试点。


12

我为gVim和命令行Vim使用相同的.vimrc文件。我倾向于在gVim中使用选项卡,并在命令行Vim中使用缓冲区,因此我设置了.vimrc以便于使用它们更加容易:

" Movement between tabs OR buffers
nnoremap L :call MyNext()<CR>
nnoremap H :call MyPrev()<CR>

" MyNext() and MyPrev(): Movement between tabs OR buffers
function! MyNext()
    if exists( '*tabpagenr' ) && tabpagenr('$') != 1
        " Tab support && tabs open
        normal gt
    else
        " No tab support, or no tabs open
        execute ":bnext"
    endif
endfunction
function! MyPrev()
    if exists( '*tabpagenr' ) && tabpagenr('$') != '1'
        " Tab support && tabs open
        normal gT
    else
        " No tab support, or no tabs open
        execute ":bprev"
    endif
endfunction

这会掩盖了H和的现有映射L,但使文件之间的切换非常快捷和容易。只需点击H下一个和L上一个;无论您使用制表符还是缓冲区,都将获得预期的结果。


1
我喜欢这些映射。也可以尝试按Ctrl-H,Ctrl-L。我使用相同的映射设置了Firefox和gnome终端。具有一致的Tab键快捷键非常好。
cmcginty

4
使用领导者键而不是ctrl来避免破坏现有映射
aehlke 2010年

10

如果您要使用多个缓冲区,我认为最重要的是将其设置为hidden,以便即使您要保留的缓冲区中未保存的更改也可以让您切换缓冲区。


9

如果 仅使用vim内置命令,我见过的最好的在多个缓冲区之间切换的命令是:

nnoremap <Leader>f :set nomore<Bar>:ls<Bar>:set more<CR>:b<Space>

它完美地结合了命令:ls:b命令-列出所有打开的缓冲区,并等待您输入命令以切换缓冲区。

鉴于以上在vimrc中的映射,您键入 <Leader>f

  • 显示所有打开的缓冲区
  • 您可以:
    • 类型 23以转到缓冲区23,
    • 类型 #以转到备用/ MRU缓冲区,
    • 输入文件的部分名称,然后输入<Tab><C-i>要自动完成,
    • 或者只是<CR><Esc>留在当前缓冲区

上面的键映射的输出快照是:

:set nomore|:ls|:set more
  1  h    "script.py"    line 1
  2 #h  + "file1.txt"    line 6  -- '#' for alternative buffer
  3 %a    "README.md"    line 17 -- '%' for current buffer
  4       "file3.txt"    line 0  -- line 0 for hasn't switched to
  5     + "/etc/passwd"  line 42 -- '+' for modified
:b '<Cursor> here'

在上面的快照中:

  • 第二列:%a当前,h隐藏,#对于上一个,未切换为空。
  • 第三栏:+用于修改。

另外,我强烈建议set hidden。请参阅:help 'hidden'


这是一个好主意!我一直在使用:b:ls但经常独立使用。我认为,当您拥有的页面缓冲区不止一个缓冲区时,此功能将不再有用,但是您仍然可以回到:b
icc97'9

很高兴看到它有帮助。干杯! :)
qeatzy

从这个Vim wikia上,您可以将其缩短到nnoremap <leader>f :ls<cr>:b<space>,虽然可能会遇到'more'命令的问题
icc97

是的,如果打开的文件较少(通常使用的情况),这种方法将非常有效。 set more只有在打开了许多文件(超过一页)时,东西才有所不同,例如vim /usr/include/*,尽管用处不大。
qeatzy

8

我使用以下内容,这为您提供了您期望在其他编辑器中拥有的许多功能,例如Sublime Text / Textmate

  1. 使用缓冲区而不是“标签页”。缓冲区与几乎所有其他编辑器中的选项卡具有相同的概念。
  2. 如果您希望具有标签的外观,则可以在以下代码中使用带有以下设置的vim-airline插件.vimrclet g:airline#extensions#tabline#enabled = 1。当您没有打开标签页时,这会自动将所有缓冲区显示为标签页标题
  3. 使用Tim Pope的vim-unimpaired分别给定[b]b移至上一个/下一个缓冲区(以及大量其他东西)
  4. set wildmenu.vimrc那么当你输入:b <file part>+Tab一个缓冲,你会得到可能的缓冲区的列表,你可以使用左/右箭头键滚动
  5. 使用Tim Pope的vim-obsession插件来存储可以与航空公司完美配合的会话(我对会话和插件感到很痛苦
  6. 使用Tim Pope的vim-vinegar插件。这可以与本机一起使用,:Explore但是使用起来更容易。您只需键入-以打开资源管理器,这与在资源管理器中进入目录的键相同。使导航更快(但是对于fzf,我很少使用此功能)
  7. fzf(可以作为vim插件安装)也是一个非常强大的模糊查找器,可用于搜索文件(以及缓冲区)。fzf 与fd(find的更快版本)的配合也很好
  8. Ripgrepvim-ripgrep一起使用以搜索代码库,然后可以使用:cdo结果进行搜索和替换

fzf和fzf-vim改变了我的生活,不能推荐它。它甚至在控制台中模糊搜索文件的Windows上也很好用。在Windows上,请使用ripgrep(rg)后端,以我的经验,该后端要胜过其他任何find / grep工具(例如silversearcher或de default Windows会发现fzf使用iirc)。您可以使用它搜索任何项目列表:最近使用过的文件,当前打开的缓冲区,当前缓冲区中的行,代码库(cwd)中的行,标签等..您可以轻松地编写自己的列表模糊搜索。超好的!(我来自ctrl-p,从不回头)
Emile Vrijdags

7

有效处理多个文件的方法是使用tmux。

它允许您垂直和水平分割窗口,如下所示:

在此处输入图片说明

我在Mac和Linux机器上都以这种方式工作,并且发现它比提供的(在Mac上)本机窗口窗格切换机制更好。我发现切换更容易,并且只有使用tmux才能在Mac上运行“在当前目录中的新页面”(尽管事实是似乎存在在同一目录中打开新窗格的选项)。一个非常关键的部分。当前位置的即时新窗格非常有用。对于我来说,使用两个操作系统具有相同按键组合的新窗格的方法对我来说至关重要,而对所有人而言,这是一个额外的好处,因为它们可以实现未来的个人兼容性。除了多个tmux窗格,我还尝试使用多个选项卡,例如在此处输入图片说明和多个新窗口(例如)在此处输入图片说明最终我发现多个tmux窗格对我来说最有用。我非常“视觉化”,喜欢将各种环境摆在我面前,就像窗格一样。

tmux还支持较早版本screen不支持的水平和垂直窗格(尽管mac的iterm2似乎支持它,但是同样,当前目录设置对我不起作用)。tmux 1.8


1
当我看到您的“多个窗口”的人工示例时,我不得不大笑。我希望没有人像这样工作:-)无论如何,我使用了更好的切片wm(我从tmux切换到i3wm)。只是为了完成您的答案。
lzap 2014年

1
Tmux很棒,我使用这种方法已经很长时间了,但是它使导航和在两个文件之间复制和粘贴变得更加困难。
否定

1
我曾经这样做过,但是当您需要拉取/粘贴内容时,拥有多个vim缓冲区是更好的选择
Titou

3

我经常使用命令行和git,因此我的bashrc中有以下别名:

alias gvim="gvim --servername \$(git rev-parse --show-toplevel || echo 'default') --remote-tab"

这将在现有窗口的新选项卡中打开每个新文件,并将为每个git存储库创建一个窗口。因此,如果您从存储库A打开两个文件,从存储库B打开三个文件,则最终将显示两个窗口,一个窗口用于带两个选项卡的存储库A,一个窗口用于三个选项卡的存储库B。

如果您要打开的文件未包含在git repo中,它将进入默认窗口。

要在选项卡之间跳转,请使用以下映射:

nmap <C-p> :tabprevious<CR>
nmap <C-n> :tabnext<CR>

要一次打开多个文件,应将其与其他解决方案之一结合使用。


3

我使用设置为隐藏在~/.vimrc文件中的多个缓冲区。

迷你缓冲区资源管理器脚本也很不错,可以很好地紧凑地列出缓冲区。然后:b1:b2...转到适当的缓冲区,或使用迷你缓冲区浏览器并在缓冲区中使用Tab键。


2

尝试以下地图以方便编辑多个文件

分割窗户

nmap <leader>sh :leftabove vnew<CR>

nmap <leader>sl :rightbelow vnew<CR>

nmap <leader>sk :leftabove new<CR>

nmap <leader>sj :rightbelow new<CR>

“ 到处走

nmap <C-j> <C-w>j

nmap <C-k> <C-w>k

nmap <C-l> <C-w>l

nmap <C-h> <C-w>h


2

我制作了一个非常简单的视频,显示了我使用的工作流程。基本上,我使用Ctrl-P Vim插件,并将缓冲区导航映射到Enter键。

这样,我可以在正常模式下按Enter键,查看打开的文件列表(在屏幕底部的一个新的小窗口中显示),选择我要编辑的文件,然后再次按Enter键。要快速搜索多个打开的文件,只需键入文件名的一部分,选择文件,然后按Enter。

我在视频中没有打开很多文件,但是当您开始拥有很多文件时,它会非常有用。

由于该插件使用MRU顺序对缓冲区进行排序,因此您只需按Enter键两次即可跳转到您正在编辑的最新文件。

安装插件后,您唯一需要的配置是:

nmap <CR> :CtrlPBuffer<CR>

当然,您可以将其映射到其他键,但是我发现要输入的映射非常方便。



2

在我和其他许多vim用户中,最好的选择是,

  • 使用打开文件,

:e file_name.extension

然后只需按Ctrl + 6即可更改为最后一个缓冲区。或者,您随时可以按

:ls列出缓冲区,然后使用b和缓冲区编号来更改缓冲区。

  • 我们使用

:vsp进行垂直分割

:sp用于水平分割

然后<C-W><C-H/K/L/j>更改工作拆分。

您当然可以编辑任意数量的分割文件。


编辑您的答案,以确保它可以改善此问题中已经存在的其他答案。
hongsy

1

当我开始使用VIM时,我没有意识到应该将选项卡用作不同的窗口布局,而缓冲区则充当着多个文件编辑/彼此切换的角色。实际上,在v7.0之前,开始时甚至没有选项卡,我只是在终端选项卡中打开了一个VIM(我当时正在使用gnome-terminal),并使用alt + numbers在选项卡之间切换,因为我认为使用的命令是:buffers,:bn和:bp对我来说太多了。当发布VIM 7.0时,我发现管理许多文件并切换到它更容易,但是最近我才意识到,缓冲区应该一直是必经之路,除非有一件事情:您需要对其进行配置以使其正常工作。

因此,我尝试了vim-airline并启用了可视化的顶部选项卡状缓冲栏,但是iTerm2出现了图形问题,因此我尝试了其他几个,MBE似乎对我来说效果最好。我还将shift + h / l设置为快捷方式,因为原始设置(移至当前页面的头部/尾部)对我来说不是很有用。

map <S-h> :bprev<Return>
map <S-l> :bnext<Return>

它似乎比gt和gT更容易,而:e也比:tabnew更容易。我发现:bd不如:q方便(MBE出现了一些问题),但我可以将所有文件放在缓冲区中。



0

该线程中的大多数答案都使用普通的vim命令,这当然很好,但是我想我会结合使用一些我认为特别有用的插件和函数来提供广泛的答案(至少其中一些技巧来自Gary Bernhardt的文件导航提示):

  1. 要在最后两个文件之间切换,只需按<leader>两次。我建议分配<leader>给空格键:

    nnoremap <leader><leader> <c-^>
    
  2. 为了快速地在项目中移动,答案是诸如CtrlP之类的模糊匹配解决方案。我将其绑定以<leader>a快速访问。

  3. 在这种情况下,我想使用BufExplorer插件直观地看到当前打开的缓冲区。简单但有效。

  4. 如果要浏览文件系统,可以使用命令行或外部实用程序(Quicklsilver,Afred等),但查看当前的项目结构NERD Tree是经典的。尽管不要将其2用作您的主要文件查找方法。这真的会让你慢下来。我使用绑定<leader>ff

这些应该足以查找和打开文件。当然,从那里使用水平和垂直拆分。关于拆分,我发现这些功能特别有用:

  1. 如果没有足够的空间,请在较小的区域中打开新的拆分,然后在导航中进行扩展。有关这些功能的确切注释,请参见此处

    set winwidth=84
    set winheight=5
    set winminheight=5
    set winheight=999
    
    nnoremap <C-w>v :111vs<CR>
    nnoremap <C-w>s :rightbelow split<CR>
    set splitright
    
  2. 从拆分轻松地拆分:

    nnoremap <C-J> <C-W><C-J>
    nnoremap <C-K> <C-W><C-K>
    nnoremap <C-L> <C-W><C-L>
    nnoremap <C-H> <C-W><C-H>
    

0

你可以是一个绝对的疯子和别名vim,以vim -p在您的加入.bashrc

alias vim="vim -p"

这将导致从shell中的选项卡中打开多个文件,而无需:tab ball随后从vim内部调用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.