ibuffer.el 106 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765
  1. ;;; ibuffer.el --- operate on buffers like dired -*- lexical-binding:t -*-
  2. ;; Copyright (C) 2000-2017 Free Software Foundation, Inc.
  3. ;; Author: Colin Walters <walters@verbum.org>
  4. ;; Maintainer: John Paul Wallington <jpw@gnu.org>
  5. ;; Created: 8 Sep 2000
  6. ;; Keywords: buffer, convenience
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; ibuffer.el is an advanced replacement for the `buffer-menu' which
  20. ;; is normally distributed with Emacs. Its interface is intended to
  21. ;; be analogous to that of Dired.
  22. ;;; Code:
  23. (eval-when-compile
  24. (require 'cl-lib)
  25. (require 'ibuf-macs)
  26. (require 'dired))
  27. (require 'font-core)
  28. (require 'seq)
  29. (require 'ibuffer-loaddefs)
  30. ;; These come from ibuf-ext.el, which can not be require'd at compile time
  31. ;; because it has a recursive dependency on ibuffer.el
  32. (defvar ibuffer-auto-mode)
  33. (defvar ibuffer-cached-filter-formats)
  34. (defvar ibuffer-compiled-filter-formats)
  35. (defvar ibuffer-filter-format-alist)
  36. (defvar ibuffer-filter-group-kill-ring)
  37. (defvar ibuffer-filter-groups)
  38. (defvar ibuffer-filtering-qualifiers)
  39. (defvar ibuffer-header-line-format)
  40. (defvar ibuffer-hidden-filter-groups)
  41. (defvar ibuffer-inline-columns)
  42. (defvar ibuffer-show-empty-filter-groups)
  43. (defvar ibuffer-tmp-hide-regexps)
  44. (defvar ibuffer-tmp-show-regexps)
  45. (declare-function ibuffer-ext-visible-p "ibuf-ext"
  46. (buf all &optional ibuffer-buf))
  47. (declare-function ibuffer-mark-on-buffer "ibuf-ext"
  48. (func &optional ibuffer-mark-on-buffer-mark group))
  49. (declare-function ibuffer-generate-filter-groups "ibuf-ext"
  50. (bmarklist &optional noempty nodefault))
  51. (declare-function ibuffer-format-filter-group-data "ibuf-ext" (filter))
  52. (defgroup ibuffer nil
  53. "Advanced replacement for `buffer-menu'.
  54. Ibuffer lets you operate on buffers in a Dired-like way,
  55. with the ability to sort, mark by regular expression,
  56. and filter displayed buffers by various criteria."
  57. :version "22.1"
  58. :group 'convenience)
  59. (defcustom ibuffer-formats '((mark modified read-only locked
  60. " " (name 18 18 :left :elide)
  61. " " (size 9 -1 :right)
  62. " " (mode 16 16 :left :elide) " " filename-and-process)
  63. (mark " " (name 16 -1) " " filename))
  64. "A list of ways to display buffer lines.
  65. With Ibuffer, you are not limited to displaying just certain
  66. attributes of a buffer such as size, name, and mode in a particular
  67. order. Through this variable, you can completely customize and
  68. control the appearance of an Ibuffer buffer. See also
  69. `define-ibuffer-column', which allows you to define your own columns
  70. for display.
  71. This variable has the form
  72. ((COLUMN COLUMN ...) (COLUMN COLUMN ...) ...)
  73. Each element in `ibuffer-formats' should be a list containing COLUMN
  74. specifiers. A COLUMN can be any of the following:
  75. SYMBOL - A symbol naming the column. Predefined columns are:
  76. mark modified read-only locked name size mode process filename
  77. When you define your own columns using `define-ibuffer-column', just
  78. use their name like the predefined columns here. This entry can
  79. also be a function of two arguments, which should return a string.
  80. The first argument is the buffer object, and the second is the mark
  81. on that buffer.
  82. or
  83. \"STRING\" - A literal string to display.
  84. or
  85. (SYMBOL MIN-SIZE MAX-SIZE &optional ALIGN ELIDE) - SYMBOL is a
  86. symbol naming the column, and MIN-SIZE and MAX-SIZE are integers (or
  87. functions of no arguments returning an integer) which constrict the
  88. size of a column. If MAX-SIZE is -1, there is no upper bound. The
  89. default values are 0 and -1, respectively. If MIN-SIZE is negative,
  90. use the end of the string. The optional element ALIGN describes the
  91. alignment of the column; it can be :left, :center or :right. The
  92. optional element ELIDE describes whether or not to elide the column
  93. if it is too long; valid values are :elide and nil. The default is
  94. nil (don't elide).
  95. Some example of valid entries in `ibuffer-formats', with
  96. description (also, feel free to try them out, and experiment with your
  97. own!):
  98. (mark \" \" name)
  99. This format just displays the current mark (if any) and the name of
  100. the buffer, separated by a space.
  101. (mark modified read-only \" \" (name 16 16 :left) \" \" (size 6 -1 :right))
  102. This format displays the current mark (if any), its modification and
  103. read-only status, as well as the name of the buffer and its size. In
  104. this format, the name is restricted to 16 characters (longer names
  105. will be truncated, and shorter names will be padded with spaces), and
  106. the name is also aligned to the left. The size of the buffer will
  107. be padded with spaces up to a minimum of six characters, but there is
  108. no upper limit on its size. The size will also be aligned to the
  109. right.
  110. Thus, if you wanted to use these two formats, the appropriate
  111. value for this variable would be
  112. \\='((mark \" \" name)
  113. (mark modified read-only
  114. (name 16 16 :left)
  115. (size 6 -1 :right)))
  116. Using \\[ibuffer-switch-format], you can rotate the display between
  117. the specified formats in the list."
  118. :version "26.1"
  119. :type '(repeat sexp)
  120. :group 'ibuffer)
  121. (defcustom ibuffer-always-compile-formats (featurep 'bytecomp)
  122. "If non-nil, then use the byte-compiler to optimize `ibuffer-formats'.
  123. This will increase the redisplay speed, at the cost of loading the
  124. elisp byte-compiler."
  125. :type 'boolean
  126. :group 'ibuffer)
  127. (defcustom ibuffer-fontification-alist
  128. `((10 buffer-read-only font-lock-constant-face)
  129. (15 (and buffer-file-name
  130. (string-match ibuffer-compressed-file-name-regexp
  131. buffer-file-name))
  132. font-lock-doc-face)
  133. (20 (string-match "^*" (buffer-name)) font-lock-keyword-face)
  134. (25 (and (string-match "^ " (buffer-name))
  135. (null buffer-file-name))
  136. italic)
  137. (30 (memq major-mode ibuffer-help-buffer-modes) font-lock-comment-face)
  138. (35 (derived-mode-p 'dired-mode) font-lock-function-name-face)
  139. (40 (and (boundp 'emacs-lock-mode) emacs-lock-mode) ibuffer-locked-buffer))
  140. "An alist describing how to fontify buffers.
  141. Each element should be of the form (PRIORITY FORM FACE), where
  142. PRIORITY is an integer, FORM is an arbitrary form to evaluate in the
  143. buffer, and FACE is the face to use for fontification. If the FORM
  144. evaluates to non-nil, then FACE will be put on the buffer name. The
  145. element with the highest PRIORITY takes precedence.
  146. If you change this variable, you must kill the Ibuffer buffer and
  147. recreate it for the change to take effect."
  148. :type '(repeat
  149. (list (integer :tag "Priority")
  150. (sexp :tag "Test Form")
  151. face))
  152. :group 'ibuffer)
  153. (defcustom ibuffer-use-other-window nil
  154. "If non-nil, display Ibuffer in another window by default."
  155. :type 'boolean
  156. :group 'ibuffer)
  157. (defcustom ibuffer-default-shrink-to-minimum-size nil
  158. "If non-nil, minimize the size of the Ibuffer window by default."
  159. :type 'boolean
  160. :group 'ibuffer)
  161. (defvar ibuffer-shrink-to-minimum-size nil)
  162. (defcustom ibuffer-display-summary t
  163. "If non-nil, summarize Ibuffer columns."
  164. :type 'boolean
  165. :group 'ibuffer)
  166. (defcustom ibuffer-truncate-lines t
  167. "If non-nil, do not display continuation lines."
  168. :type 'boolean
  169. :group 'ibuffer)
  170. (defcustom ibuffer-case-fold-search case-fold-search
  171. "If non-nil, ignore case when searching."
  172. :type 'boolean
  173. :group 'ibuffer)
  174. (defcustom ibuffer-default-sorting-mode 'recency
  175. "The criteria by which to sort the buffers.
  176. Note that this variable is local to each Ibuffer buffer. Thus, you
  177. can have multiple Ibuffer buffers open, each with a different sorted
  178. view of the buffers."
  179. :type '(choice (const :tag "Last view time" :value recency)
  180. (const :tag "Lexicographic" :value alphabetic)
  181. (const :tag "Buffer size" :value size)
  182. (const :tag "File name" :value filename/process)
  183. (const :tag "Major mode" :value major-mode))
  184. :group 'ibuffer)
  185. (defvar ibuffer-sorting-mode nil)
  186. (defvar ibuffer-last-sorting-mode nil)
  187. (defcustom ibuffer-default-sorting-reversep nil
  188. "If non-nil, reverse the default sorting order."
  189. :type 'boolean
  190. :group 'ibuffer)
  191. (defvar ibuffer-sorting-reversep nil)
  192. (defcustom ibuffer-elide-long-columns nil
  193. "If non-nil, then elide column entries which exceed their max length."
  194. :type 'boolean
  195. :group 'ibuffer)
  196. (make-obsolete-variable 'ibuffer-elide-long-columns
  197. "use the :elide argument of `ibuffer-formats'."
  198. "22.1")
  199. (defcustom ibuffer-eliding-string "..."
  200. "The string to use for eliding long columns."
  201. :type 'string
  202. :group 'ibuffer)
  203. (defcustom ibuffer-maybe-show-predicates `(,(lambda (buf)
  204. (and (string-match "^ " (buffer-name buf))
  205. (null buffer-file-name))))
  206. "A list of predicates for buffers to display conditionally.
  207. A predicate can be a regexp or a function.
  208. If a regexp, then it will be matched against the buffer's name.
  209. If a function, it will be called with the buffer as an argument, and
  210. should return non-nil if this buffer should be shown.
  211. Viewing of buffers hidden because of these predicates may be customized
  212. via `ibuffer-default-display-maybe-show-predicates' and is toggled by
  213. giving a non-nil prefix argument to `ibuffer-update'.
  214. Note that this specialized filtering occurs before real filtering."
  215. :type '(repeat (choice regexp function))
  216. :group 'ibuffer)
  217. (defcustom ibuffer-default-display-maybe-show-predicates nil
  218. "Non-nil means show buffers that match `ibuffer-maybe-show-predicates'."
  219. :type 'boolean
  220. :group 'ibuffer)
  221. (defvar ibuffer-display-maybe-show-predicates nil)
  222. (defvar ibuffer-current-format nil)
  223. (defcustom ibuffer-movement-cycle t
  224. "If non-nil, then forward and backwards movement commands cycle."
  225. :type 'boolean
  226. :group 'ibuffer)
  227. (defcustom ibuffer-modified-char ?*
  228. "The character to display for modified buffers."
  229. :type 'character
  230. :group 'ibuffer)
  231. (defcustom ibuffer-read-only-char ?%
  232. "The character to display for read-only buffers."
  233. :type 'character
  234. :group 'ibuffer)
  235. (defcustom ibuffer-marked-char ?>
  236. "The character to display for marked buffers."
  237. :type 'character
  238. :group 'ibuffer)
  239. (defcustom ibuffer-locked-char ?L
  240. "The character to display for locked buffers."
  241. :version "26.1"
  242. :type 'character
  243. :group 'ibuffer)
  244. (defcustom ibuffer-deletion-char ?D
  245. "The character to display for buffers marked for deletion."
  246. :type 'character
  247. :group 'ibuffer)
  248. (defcustom ibuffer-expert nil
  249. "If non-nil, don't ask for confirmation of \"dangerous\" operations."
  250. :type 'boolean
  251. :group 'ibuffer)
  252. (defcustom ibuffer-view-ibuffer nil
  253. "If non-nil, display the current Ibuffer buffer itself.
  254. Note that this has a drawback - the data about the current Ibuffer
  255. buffer will most likely be inaccurate. This includes modification
  256. state, size, etc."
  257. :type 'boolean
  258. :group 'ibuffer)
  259. (defcustom ibuffer-always-show-last-buffer nil
  260. "If non-nil, always display the previous buffer.
  261. This variable takes precedence over filtering, and even
  262. `ibuffer-never-show-predicates'."
  263. :type '(choice (const :tag "Always" :value t)
  264. (const :tag "Never" :value nil)
  265. (const :tag "Always except minibuffer" :value :nomini))
  266. :group 'ibuffer)
  267. (defcustom ibuffer-jump-offer-only-visible-buffers nil
  268. "If non-nil, only offer buffers visible in the Ibuffer buffer
  269. in completion lists of the `ibuffer-jump-to-buffer' command."
  270. :type 'boolean
  271. :group 'ibuffer)
  272. (defcustom ibuffer-use-header-line (boundp 'header-line-format)
  273. "If non-nil, display a header line containing current filters."
  274. :type 'boolean
  275. :group 'ibuffer)
  276. (defcustom ibuffer-default-directory nil
  277. "The default directory to use for a new Ibuffer buffer.
  278. If nil, inherit the directory of the buffer in which `ibuffer' was
  279. called. Otherwise, this variable should be a string naming a
  280. directory, like `default-directory'."
  281. :type '(choice (const :tag "Inherit" :value nil)
  282. string)
  283. :group 'ibuffer)
  284. (defcustom ibuffer-help-buffer-modes
  285. '(help-mode apropos-mode Info-mode Info-edit-mode)
  286. "List of \"Help\" major modes."
  287. :type '(repeat function)
  288. :group 'ibuffer)
  289. (defcustom ibuffer-compressed-file-name-regexp
  290. "\\.\\(arj\\|bgz\\|bz2\\|gz\\|lzh\\|taz\\|tgz\\|xz\\|zip\\|z\\)$"
  291. "Regexp to match compressed file names."
  292. :version "24.1" ; added xz
  293. :type 'regexp
  294. :group 'ibuffer)
  295. (define-obsolete-variable-alias 'ibuffer-hooks 'ibuffer-hook "22.1")
  296. (defcustom ibuffer-hook nil
  297. "Hook run when `ibuffer' is called."
  298. :type 'hook
  299. :group 'ibuffer)
  300. (define-obsolete-variable-alias 'ibuffer-mode-hooks 'ibuffer-mode-hook "22.1")
  301. (defcustom ibuffer-mode-hook nil
  302. "Hook run upon entry into `ibuffer-mode'."
  303. :type 'hook
  304. :options '(ibuffer-auto-mode)
  305. :group 'ibuffer)
  306. (defcustom ibuffer-load-hook nil
  307. "Hook run when Ibuffer is loaded."
  308. :type 'hook
  309. :group 'ibuffer)
  310. (defcustom ibuffer-marked-face 'warning
  311. "Face used for displaying marked buffers."
  312. :type 'face
  313. :group 'ibuffer)
  314. (defcustom ibuffer-deletion-face 'error
  315. "Face used for displaying buffers marked for deletion."
  316. :type 'face
  317. :group 'ibuffer)
  318. (defcustom ibuffer-title-face 'font-lock-type-face
  319. "Face used for the title string."
  320. :type 'face
  321. :group 'ibuffer)
  322. (defcustom ibuffer-filter-group-name-face 'bold
  323. "Face used for displaying filtering group names."
  324. :type 'face
  325. :group 'ibuffer)
  326. (defcustom ibuffer-directory-abbrev-alist nil
  327. "An alist of file name abbreviations like `directory-abbrev-alist'."
  328. :type '(repeat (cons :format "%v"
  329. :value ("" . "")
  330. (regexp :tag "From")
  331. (regexp :tag "To")))
  332. :group 'ibuffer)
  333. (defvar ibuffer-mode-groups-popup
  334. (let ((groups-map (make-sparse-keymap "Filter Groups")))
  335. ;; Filter groups
  336. (define-key-after groups-map [filters-to-filter-group]
  337. '(menu-item "Create filter group from current filters..."
  338. ibuffer-filters-to-filter-group
  339. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
  340. (define-key-after groups-map [forward-filter-group]
  341. '(menu-item "Move point to the next filter group"
  342. ibuffer-forward-filter-group))
  343. (define-key-after groups-map [backward-filter-group]
  344. '(menu-item "Move point to the previous filter group"
  345. ibuffer-backward-filter-group))
  346. (define-key-after groups-map [jump-to-filter-group]
  347. '(menu-item "Move point to a specific filter group..."
  348. ibuffer-jump-to-filter-group))
  349. (define-key-after groups-map [kill-filter-group]
  350. '(menu-item "Kill filter group named..."
  351. ibuffer-kill-filter-group
  352. :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
  353. (define-key-after groups-map [yank-filter-group]
  354. '(menu-item "Yank last killed filter group before..."
  355. ibuffer-yank-filter-group
  356. :enable (and (featurep 'ibuf-ext) ibuffer-filter-group-kill-ring)))
  357. (define-key-after groups-map [pop-filter-group]
  358. '(menu-item "Remove top filter group"
  359. ibuffer-pop-filter-group
  360. :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
  361. (define-key-after groups-map [clear-filter-groups]
  362. '(menu-item "Remove all filter groups"
  363. ibuffer-clear-filter-groups
  364. :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
  365. (define-key-after groups-map [pop-filter-group]
  366. '(menu-item "Decompose filter group..."
  367. ibuffer-pop-filter-group
  368. :help "\"Unmake\" a filter group"
  369. :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)))
  370. (define-key-after groups-map [save-filter-groups]
  371. '(menu-item "Save current filter groups permanently..."
  372. ibuffer-save-filter-groups
  373. :enable (and (featurep 'ibuf-ext) ibuffer-filter-groups)
  374. :help "Use a mnemonic name to store current filter groups"))
  375. (define-key-after groups-map [switch-to-saved-filter-groups]
  376. '(menu-item "Restore permanently saved filters..."
  377. ibuffer-switch-to-saved-filter-groups
  378. :enable (and (featurep 'ibuf-ext) ibuffer-saved-filter-groups)
  379. :help "Replace current filters with a saved stack"))
  380. (define-key-after groups-map [delete-saved-filter-groups]
  381. '(menu-item "Delete permanently saved filter groups..."
  382. ibuffer-delete-saved-filter-groups
  383. :enable (and (featurep 'ibuf-ext) ibuffer-saved-filter-groups)))
  384. (define-key-after groups-map [set-filter-groups-by-mode]
  385. '(menu-item "Set current filter groups to filter by mode"
  386. ibuffer-set-filter-groups-by-mode))
  387. groups-map))
  388. (defvar ibuffer-mode-map
  389. (let ((map (make-keymap)))
  390. (define-key map (kbd "0") 'digit-argument)
  391. (define-key map (kbd "1") 'digit-argument)
  392. (define-key map (kbd "2") 'digit-argument)
  393. (define-key map (kbd "3") 'digit-argument)
  394. (define-key map (kbd "4") 'digit-argument)
  395. (define-key map (kbd "5") 'digit-argument)
  396. (define-key map (kbd "6") 'digit-argument)
  397. (define-key map (kbd "7") 'digit-argument)
  398. (define-key map (kbd "8") 'digit-argument)
  399. (define-key map (kbd "9") 'digit-argument)
  400. (define-key map (kbd "m") 'ibuffer-mark-forward)
  401. (define-key map (kbd "t") 'ibuffer-toggle-marks)
  402. (define-key map (kbd "u") 'ibuffer-unmark-forward)
  403. (define-key map (kbd "=") 'ibuffer-diff-with-file)
  404. (define-key map (kbd "j") 'ibuffer-jump-to-buffer)
  405. (define-key map (kbd "M-g") 'ibuffer-jump-to-buffer)
  406. (define-key map (kbd "M-s a C-s") 'ibuffer-do-isearch)
  407. (define-key map (kbd "M-s a M-C-s") 'ibuffer-do-isearch-regexp)
  408. (define-key map (kbd "M-s a C-o") 'ibuffer-do-occur)
  409. (define-key map (kbd "DEL") 'ibuffer-unmark-backward)
  410. (define-key map (kbd "M-DEL") 'ibuffer-unmark-all)
  411. (define-key map (kbd "* *") 'ibuffer-unmark-all)
  412. (define-key map (kbd "* c") 'ibuffer-change-marks)
  413. (define-key map (kbd "U") 'ibuffer-unmark-all-marks)
  414. (define-key map (kbd "* M") 'ibuffer-mark-by-mode)
  415. (define-key map (kbd "* m") 'ibuffer-mark-modified-buffers)
  416. (define-key map (kbd "* u") 'ibuffer-mark-unsaved-buffers)
  417. (define-key map (kbd "* s") 'ibuffer-mark-special-buffers)
  418. (define-key map (kbd "* r") 'ibuffer-mark-read-only-buffers)
  419. (define-key map (kbd "* /") 'ibuffer-mark-dired-buffers)
  420. (define-key map (kbd "* e") 'ibuffer-mark-dissociated-buffers)
  421. (define-key map (kbd "* h") 'ibuffer-mark-help-buffers)
  422. (define-key map (kbd "* z") 'ibuffer-mark-compressed-file-buffers)
  423. (define-key map (kbd ".") 'ibuffer-mark-old-buffers)
  424. (define-key map (kbd "d") 'ibuffer-mark-for-delete)
  425. (define-key map (kbd "C-d") 'ibuffer-mark-for-delete-backwards)
  426. (define-key map (kbd "k") 'ibuffer-mark-for-delete)
  427. (define-key map (kbd "x") 'ibuffer-do-kill-on-deletion-marks)
  428. ;; immediate operations
  429. (define-key map (kbd "n") 'ibuffer-forward-line)
  430. (define-key map (kbd "SPC") 'forward-line)
  431. (define-key map (kbd "p") 'ibuffer-backward-line)
  432. (define-key map (kbd "M-}") 'ibuffer-forward-next-marked)
  433. (define-key map (kbd "M-{") 'ibuffer-backwards-next-marked)
  434. (define-key map (kbd "l") 'ibuffer-redisplay)
  435. (define-key map (kbd "g") 'ibuffer-update)
  436. (define-key map "`" 'ibuffer-switch-format)
  437. (define-key map "-" 'ibuffer-add-to-tmp-hide)
  438. (define-key map "+" 'ibuffer-add-to-tmp-show)
  439. (define-key map "b" 'ibuffer-bury-buffer)
  440. (define-key map (kbd ",") 'ibuffer-toggle-sorting-mode)
  441. (define-key map (kbd "s i") 'ibuffer-invert-sorting)
  442. (define-key map (kbd "s a") 'ibuffer-do-sort-by-alphabetic)
  443. (define-key map (kbd "s v") 'ibuffer-do-sort-by-recency)
  444. (define-key map (kbd "s s") 'ibuffer-do-sort-by-size)
  445. (define-key map (kbd "s f") 'ibuffer-do-sort-by-filename/process)
  446. (define-key map (kbd "s m") 'ibuffer-do-sort-by-major-mode)
  447. (define-key map (kbd "/ RET") 'ibuffer-filter-by-mode)
  448. (define-key map (kbd "/ m") 'ibuffer-filter-by-used-mode)
  449. (define-key map (kbd "/ M") 'ibuffer-filter-by-derived-mode)
  450. (define-key map (kbd "/ n") 'ibuffer-filter-by-name)
  451. (define-key map (kbd "/ *") 'ibuffer-filter-by-starred-name)
  452. (define-key map (kbd "/ f") 'ibuffer-filter-by-filename)
  453. (define-key map (kbd "/ b") 'ibuffer-filter-by-basename)
  454. (define-key map (kbd "/ .") 'ibuffer-filter-by-file-extension)
  455. (define-key map (kbd "/ <") 'ibuffer-filter-by-size-lt)
  456. (define-key map (kbd "/ >") 'ibuffer-filter-by-size-gt)
  457. (define-key map (kbd "/ i") 'ibuffer-filter-by-modified)
  458. (define-key map (kbd "/ v") 'ibuffer-filter-by-visiting-file)
  459. (define-key map (kbd "/ c") 'ibuffer-filter-by-content)
  460. (define-key map (kbd "/ e") 'ibuffer-filter-by-predicate)
  461. (define-key map (kbd "/ r") 'ibuffer-switch-to-saved-filters)
  462. (define-key map (kbd "/ a") 'ibuffer-add-saved-filters)
  463. (define-key map (kbd "/ x") 'ibuffer-delete-saved-filters)
  464. (define-key map (kbd "/ d") 'ibuffer-decompose-filter)
  465. (define-key map (kbd "/ s") 'ibuffer-save-filters)
  466. (define-key map (kbd "/ p") 'ibuffer-pop-filter)
  467. (define-key map (kbd "/ <up>") 'ibuffer-pop-filter)
  468. (define-key map (kbd "/ !") 'ibuffer-negate-filter)
  469. (define-key map (kbd "/ t") 'ibuffer-exchange-filters)
  470. (define-key map (kbd "/ TAB") 'ibuffer-exchange-filters)
  471. (define-key map (kbd "/ o") 'ibuffer-or-filter)
  472. (define-key map (kbd "/ |") 'ibuffer-or-filter)
  473. (define-key map (kbd "/ &") 'ibuffer-and-filter)
  474. (define-key map (kbd "/ g") 'ibuffer-filters-to-filter-group)
  475. (define-key map (kbd "/ P") 'ibuffer-pop-filter-group)
  476. (define-key map (kbd "/ S-<up>") 'ibuffer-pop-filter-group)
  477. (define-key map (kbd "/ D") 'ibuffer-decompose-filter-group)
  478. (define-key map (kbd "/ /") 'ibuffer-filter-disable)
  479. (define-key map (kbd "M-n") 'ibuffer-forward-filter-group)
  480. (define-key map "\t" 'ibuffer-forward-filter-group)
  481. (define-key map (kbd "M-p") 'ibuffer-backward-filter-group)
  482. (define-key map [backtab] 'ibuffer-backward-filter-group)
  483. (define-key map (kbd "M-j") 'ibuffer-jump-to-filter-group)
  484. (define-key map (kbd "C-k") 'ibuffer-kill-line)
  485. (define-key map (kbd "C-y") 'ibuffer-yank)
  486. (define-key map (kbd "/ S") 'ibuffer-save-filter-groups)
  487. (define-key map (kbd "/ R") 'ibuffer-switch-to-saved-filter-groups)
  488. (define-key map (kbd "/ X") 'ibuffer-delete-saved-filter-groups)
  489. (define-key map (kbd "/ \\") 'ibuffer-clear-filter-groups)
  490. (define-key map (kbd "% n") 'ibuffer-mark-by-name-regexp)
  491. (define-key map (kbd "% m") 'ibuffer-mark-by-mode-regexp)
  492. (define-key map (kbd "% f") 'ibuffer-mark-by-file-name-regexp)
  493. (define-key map (kbd "% g") 'ibuffer-mark-by-content-regexp)
  494. (define-key map (kbd "% L") 'ibuffer-mark-by-locked)
  495. (define-key map (kbd "C-t") 'ibuffer-visit-tags-table)
  496. (define-key map (kbd "|") 'ibuffer-do-shell-command-pipe)
  497. (define-key map (kbd "!") 'ibuffer-do-shell-command-file)
  498. (define-key map (kbd "~") 'ibuffer-do-toggle-modified)
  499. ;; marked operations
  500. (define-key map (kbd "A") 'ibuffer-do-view)
  501. (define-key map (kbd "D") 'ibuffer-do-delete)
  502. (define-key map (kbd "E") 'ibuffer-do-eval)
  503. (define-key map (kbd "F") 'ibuffer-do-shell-command-file)
  504. (define-key map (kbd "I") 'ibuffer-do-query-replace-regexp)
  505. (define-key map (kbd "H") 'ibuffer-do-view-other-frame)
  506. (define-key map (kbd "N") 'ibuffer-do-shell-command-pipe-replace)
  507. (define-key map (kbd "M") 'ibuffer-do-toggle-modified)
  508. (define-key map (kbd "O") 'ibuffer-do-occur)
  509. (define-key map (kbd "P") 'ibuffer-do-print)
  510. (define-key map (kbd "Q") 'ibuffer-do-query-replace)
  511. (define-key map (kbd "R") 'ibuffer-do-rename-uniquely)
  512. (define-key map (kbd "S") 'ibuffer-do-save)
  513. (define-key map (kbd "T") 'ibuffer-do-toggle-read-only)
  514. (define-key map (kbd "r") 'ibuffer-do-replace-regexp)
  515. (define-key map (kbd "V") 'ibuffer-do-revert)
  516. (define-key map (kbd "W") 'ibuffer-do-view-and-eval)
  517. (define-key map (kbd "X") 'ibuffer-do-shell-command-pipe)
  518. (define-key map (kbd "k") 'ibuffer-do-kill-lines)
  519. (define-key map (kbd "w") 'ibuffer-copy-filename-as-kill)
  520. (define-key map (kbd "B") 'ibuffer-copy-buffername-as-kill)
  521. (define-key map (kbd "RET") 'ibuffer-visit-buffer)
  522. (define-key map (kbd "e") 'ibuffer-visit-buffer)
  523. (define-key map (kbd "f") 'ibuffer-visit-buffer)
  524. (define-key map (kbd "C-x C-f") 'ibuffer-find-file)
  525. (define-key map (kbd "o") 'ibuffer-visit-buffer-other-window)
  526. (define-key map (kbd "C-o") 'ibuffer-visit-buffer-other-window-noselect)
  527. (define-key map (kbd "M-o") 'ibuffer-visit-buffer-1-window)
  528. (define-key map (kbd "v") 'ibuffer-do-view)
  529. (define-key map (kbd "C-x v") 'ibuffer-do-view-horizontally)
  530. (define-key map (kbd "C-c C-a") 'ibuffer-auto-mode)
  531. (define-key map (kbd "C-x 4 RET") 'ibuffer-visit-buffer-other-window)
  532. (define-key map (kbd "C-x 5 RET") 'ibuffer-visit-buffer-other-frame)
  533. (define-key map [menu-bar view]
  534. (cons "View" (make-sparse-keymap "View")))
  535. (define-key-after map [menu-bar view visit-buffer]
  536. '(menu-item "View this buffer" ibuffer-visit-buffer))
  537. (define-key-after map [menu-bar view visit-buffer-other-window]
  538. '(menu-item "View (other window)" ibuffer-visit-buffer-other-window))
  539. (define-key-after map [menu-bar view visit-buffer-other-frame]
  540. '(menu-item "View (other frame)" ibuffer-visit-buffer-other-frame))
  541. (define-key-after map [menu-bar view ibuffer-update]
  542. '(menu-item "Update" ibuffer-update
  543. :help "Regenerate the list of buffers"))
  544. (define-key-after map [menu-bar view switch-format]
  545. '(menu-item "Switch display format" ibuffer-switch-format
  546. :help "Toggle between available values of `ibuffer-formats'"))
  547. (define-key-after map [menu-bar view dashes]
  548. '("--"))
  549. (define-key-after map [menu-bar view sort]
  550. (cons "Sort" (make-sparse-keymap "Sort")))
  551. (define-key-after map [menu-bar view sort do-sort-by-major-mode]
  552. '(menu-item "Sort by major mode" ibuffer-do-sort-by-major-mode))
  553. (define-key-after map [menu-bar view sort do-sort-by-size]
  554. '(menu-item "Sort by buffer size" ibuffer-do-sort-by-size))
  555. (define-key-after map [menu-bar view sort do-sort-by-alphabetic]
  556. '(menu-item "Sort lexicographically" ibuffer-do-sort-by-alphabetic
  557. :help "Sort by the alphabetic order of buffer name"))
  558. (define-key-after map [menu-bar view sort do-sort-by-recency]
  559. '(menu-item "Sort by view time" ibuffer-do-sort-by-recency
  560. :help "Sort by the last time the buffer was displayed"))
  561. (define-key-after map [menu-bar view sort dashes]
  562. '("--"))
  563. (define-key-after map [menu-bar view sort invert-sorting]
  564. '(menu-item "Reverse sorting order" ibuffer-invert-sorting))
  565. (define-key-after map [menu-bar view sort toggle-sorting-mode]
  566. '(menu-item "Switch sorting mode" ibuffer-toggle-sorting-mode
  567. :help "Switch between the various sorting criteria"))
  568. (define-key-after map [menu-bar view filter]
  569. (cons "Filter" (make-sparse-keymap "Filter")))
  570. (define-key-after map [menu-bar view filter filter-disable]
  571. '(menu-item "Disable all filtering" ibuffer-filter-disable
  572. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
  573. (define-key-after map [menu-bar view filter filter-by-mode]
  574. '(menu-item "Add filter by any major mode..." ibuffer-filter-by-mode))
  575. (define-key-after map [menu-bar view filter filter-by-used-mode]
  576. '(menu-item "Add filter by a major mode in use..."
  577. ibuffer-filter-by-used-mode))
  578. (define-key-after map [menu-bar view filter filter-by-derived-mode]
  579. '(menu-item "Add filter by derived mode..."
  580. ibuffer-filter-by-derived-mode))
  581. (define-key-after map [menu-bar view filter filter-by-name]
  582. '(menu-item "Add filter by buffer name..." ibuffer-filter-by-name))
  583. (define-key-after map [menu-bar view filter filter-by-starred-name]
  584. '(menu-item "Add filter by starred buffer name..."
  585. ibuffer-filter-by-starred-name
  586. :help "List buffers whose names begin with a star"))
  587. (define-key-after map [menu-bar view filter filter-by-filename]
  588. '(menu-item "Add filter by full filename..." ibuffer-filter-by-filename
  589. :help
  590. (concat "For a buffer associated with file '/a/b/c.d', "
  591. "list buffer if a given pattern matches '/a/b/c.d'")))
  592. (define-key-after map [menu-bar view filter filter-by-basename]
  593. '(menu-item "Add filter by file basename..."
  594. ibuffer-filter-by-basename
  595. :help (concat "For a buffer associated with file '/a/b/c.d', "
  596. "list buffer if a given pattern matches 'c.d'")))
  597. (define-key-after map [menu-bar view filter filter-by-file-extension]
  598. '(menu-item "Add filter by file name extension..."
  599. ibuffer-filter-by-file-extension
  600. :help (concat "For a buffer associated with file '/a/b/c.d', "
  601. "list buffer if a given pattern matches 'd'")))
  602. (define-key-after map [menu-bar view filter filter-by-directory]
  603. '(menu-item "Add filter by filename's directory..."
  604. ibuffer-filter-by-directory
  605. :help
  606. (concat "For a buffer associated with file '/a/b/c.d', "
  607. "list buffer if a given pattern matches '/a/b'")))
  608. (define-key-after map [menu-bar view filter filter-by-size-lt]
  609. '(menu-item "Add filter by size less than..." ibuffer-filter-by-size-lt))
  610. (define-key-after map [menu-bar view filter filter-by-size-gt]
  611. '(menu-item "Add filter by size greater than..."
  612. ibuffer-filter-by-size-gt))
  613. (define-key-after map [menu-bar view filter filter-by-modified]
  614. '(menu-item "Add filter by modified buffer" ibuffer-filter-by-modified
  615. :help "List buffers that are marked as modified"))
  616. (define-key-after map [menu-bar view filter filter-by-visiting-file]
  617. '(menu-item "Add filter by buffer visiting a file"
  618. ibuffer-filter-by-visiting-file
  619. :help "List buffers that are visiting files"))
  620. (define-key-after map [menu-bar view filter filter-by-content]
  621. '(menu-item "Add filter by content (regexp)..."
  622. ibuffer-filter-by-content))
  623. (define-key-after map [menu-bar view filter filter-by-predicate]
  624. '(menu-item "Add filter by Lisp predicate..."
  625. ibuffer-filter-by-predicate))
  626. (define-key-after map [menu-bar view filter pop-filter]
  627. '(menu-item "Remove top filter" ibuffer-pop-filter
  628. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
  629. (define-key-after map [menu-bar view filter and-filter]
  630. '(menu-item "AND top two filters" ibuffer-and-filter
  631. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers
  632. (cdr ibuffer-filtering-qualifiers))
  633. :help
  634. "Create a new filter which is the logical AND of the top two filters"))
  635. (define-key-after map [menu-bar view filter or-filter]
  636. '(menu-item "OR top two filters" ibuffer-or-filter
  637. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers
  638. (cdr ibuffer-filtering-qualifiers))
  639. :help
  640. "Create a new filter which is the logical OR of the top two filters"))
  641. (define-key-after map [menu-bar view filter negate-filter]
  642. '(menu-item "Negate top filter" ibuffer-negate-filter
  643. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)))
  644. (define-key-after map [menu-bar view filter decompose-filter]
  645. '(menu-item "Decompose top filter" ibuffer-decompose-filter
  646. :enable (and (featurep 'ibuf-ext)
  647. (memq (car ibuffer-filtering-qualifiers) '(or saved not)))
  648. :help "Break down a complex filter like OR or NOT"))
  649. (define-key-after map [menu-bar view filter exchange-filters]
  650. '(menu-item "Swap top two filters" ibuffer-exchange-filters
  651. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers
  652. (cdr ibuffer-filtering-qualifiers))))
  653. (define-key-after map [menu-bar view filter save-filters]
  654. '(menu-item "Save current filters permanently..." ibuffer-save-filters
  655. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)
  656. :help "Use a mnemonic name to store current filter stack"))
  657. (define-key-after map [menu-bar view filter switch-to-saved-filters]
  658. '(menu-item "Restore permanently saved filters..."
  659. ibuffer-switch-to-saved-filters
  660. :enable (and (featurep 'ibuf-ext) ibuffer-saved-filters)
  661. :help "Replace current filters with a saved stack"))
  662. (define-key-after map [menu-bar view filter add-saved-filters]
  663. '(menu-item "Add to permanently saved filters..."
  664. ibuffer-add-saved-filters
  665. :enable (and (featurep 'ibuf-ext) ibuffer-filtering-qualifiers)
  666. :help "Include already saved stack with current filters"))
  667. (define-key-after map [menu-bar view filter delete-saved-filters]
  668. '(menu-item "Delete permanently saved filters..."
  669. ibuffer-delete-saved-filters
  670. :enable (and (featurep 'ibuf-ext) ibuffer-saved-filters)))
  671. (define-key-after map [menu-bar view filter-groups]
  672. (cons "Filter Groups" ibuffer-mode-groups-popup))
  673. (define-key-after map [menu-bar view dashes2]
  674. '("--"))
  675. (define-key-after map [menu-bar view auto-mode]
  676. '(menu-item "Auto Mode" ibuffer-auto-mode
  677. :button (:toggle . ibuffer-auto-mode)
  678. :help "Attempt to automatically update the Ibuffer buffer"))
  679. (define-key-after map [menu-bar mark]
  680. (cons "Mark" (make-sparse-keymap "Mark")))
  681. (define-key-after map [menu-bar mark toggle-marks]
  682. '(menu-item "Toggle marks" ibuffer-toggle-marks
  683. :help "Unmark marked buffers, and mark unmarked buffers"))
  684. (define-key-after map [menu-bar mark change-marks]
  685. '(menu-item "Change marks" ibuffer-change-marks
  686. :help "Change OLD mark for marked buffers with NEW"))
  687. (define-key-after map [menu-bar mark mark-forward]
  688. '(menu-item "Mark" ibuffer-mark-forward
  689. :help "Mark the buffer at point"))
  690. (define-key-after map [menu-bar mark unmark-forward]
  691. '(menu-item "Unmark" ibuffer-unmark-forward
  692. :help "Unmark the buffer at point"))
  693. (define-key-after map [menu-bar mark mark-by-mode]
  694. '(menu-item "Mark by mode..." ibuffer-mark-by-mode
  695. :help "Mark all buffers in a particular major mode"))
  696. (define-key-after map [menu-bar mark mark-modified-buffers]
  697. '(menu-item "Mark modified buffers" ibuffer-mark-modified-buffers
  698. :help "Mark all buffers which have been modified"))
  699. (define-key-after map [menu-bar mark mark-unsaved-buffers]
  700. '(menu-item "Mark unsaved buffers" ibuffer-mark-unsaved-buffers
  701. :help "Mark all buffers which have a file and are modified"))
  702. (define-key-after map [menu-bar mark mark-read-only-buffers]
  703. '(menu-item "Mark read-only buffers" ibuffer-mark-read-only-buffers
  704. :help "Mark all buffers which are read-only"))
  705. (define-key-after map [menu-bar mark mark-special-buffers]
  706. '(menu-item "Mark special buffers" ibuffer-mark-special-buffers
  707. :help "Mark all buffers whose name begins with a *"))
  708. (define-key-after map [menu-bar mark mark-dired-buffers]
  709. '(menu-item "Mark dired buffers" ibuffer-mark-dired-buffers
  710. :help "Mark buffers in dired-mode"))
  711. (define-key-after map [menu-bar mark mark-dissociated-buffers]
  712. '(menu-item "Mark dissociated buffers" ibuffer-mark-dissociated-buffers
  713. :help "Mark buffers with a non-existent associated file"))
  714. (define-key-after map [menu-bar mark mark-help-buffers]
  715. '(menu-item "Mark help buffers" ibuffer-mark-help-buffers
  716. :help "Mark buffers in help-mode"))
  717. (define-key-after map [menu-bar mark mark-compressed-file-buffers]
  718. '(menu-item "Mark compressed file buffers"
  719. ibuffer-mark-compressed-file-buffers
  720. :help "Mark buffers which have a file that is compressed"))
  721. (define-key-after map [menu-bar mark mark-old-buffers]
  722. '(menu-item "Mark old buffers" ibuffer-mark-old-buffers
  723. :help "Mark buffers which have not been viewed recently"))
  724. (define-key-after map [menu-bar mark unmark-all]
  725. '(menu-item "Unmark All" ibuffer-unmark-all))
  726. (define-key-after map [menu-bar mark unmark-all-marks]
  727. '(menu-item "Unmark All buffers" ibuffer-unmark-all-marks))
  728. (define-key-after map [menu-bar mark dashes]
  729. '("--"))
  730. (define-key-after map [menu-bar mark mark-by-name-regexp]
  731. '(menu-item "Mark by buffer name (regexp)..." ibuffer-mark-by-name-regexp
  732. :help "Mark buffers whose name matches a regexp"))
  733. (define-key-after map [menu-bar mark mark-by-mode-regexp]
  734. '(menu-item "Mark by major mode (regexp)..." ibuffer-mark-by-mode-regexp
  735. :help "Mark buffers whose major mode name matches a regexp"))
  736. (define-key-after map [menu-bar mark mark-by-file-name-regexp]
  737. '(menu-item "Mark by file name (regexp)..."
  738. ibuffer-mark-by-file-name-regexp
  739. :help "Mark buffers whose file name matches a regexp"))
  740. (define-key-after map [menu-bar mark ibuffer-mark-by-content-regexp]
  741. '(menu-item "Mark by content (regexp)..."
  742. ibuffer-mark-by-content-regexp
  743. :help "Mark buffers whose content matches a regexp"))
  744. (define-key-after map [menu-bar mark mark-by-locked]
  745. '(menu-item "Mark by locked buffers..." ibuffer-mark-by-locked
  746. :help "Mark all locked buffers"))
  747. map))
  748. (defvar ibuffer-mode-operate-map
  749. (let ((operate-map (make-sparse-keymap "Operate")))
  750. (define-key-after operate-map [do-view]
  751. '(menu-item "View" ibuffer-do-view))
  752. (define-key-after operate-map [do-view-other-frame]
  753. '(menu-item "View (separate frame)" ibuffer-do-view-other-frame))
  754. (define-key-after operate-map [do-save]
  755. '(menu-item "Save" ibuffer-do-save))
  756. (define-key-after operate-map [do-replace-regexp]
  757. '(menu-item "Replace (regexp)..." ibuffer-do-replace-regexp
  758. :help "Replace text inside marked buffers"))
  759. (define-key-after operate-map [do-query-replace]
  760. '(menu-item "Query Replace..." ibuffer-do-query-replace
  761. :help "Replace text in marked buffers, asking each time"))
  762. (define-key-after operate-map [do-query-replace-regexp]
  763. '(menu-item "Query Replace (regexp)..." ibuffer-do-query-replace-regexp
  764. :help "Replace text in marked buffers by regexp, asking each time"))
  765. (define-key-after operate-map [do-print]
  766. '(menu-item "Print" ibuffer-do-print))
  767. (define-key-after operate-map [do-toggle-modified]
  768. '(menu-item "Toggle modification flag" ibuffer-do-toggle-modified))
  769. (define-key-after operate-map [do-revert]
  770. '(menu-item "Revert" ibuffer-do-revert
  771. :help "Revert marked buffers to their associated file"))
  772. (define-key-after operate-map [do-rename-uniquely]
  773. '(menu-item "Rename Uniquely" ibuffer-do-rename-uniquely
  774. :help "Rename marked buffers to a new, unique name"))
  775. (define-key-after operate-map [do-delete]
  776. '(menu-item "Kill" ibuffer-do-delete))
  777. (define-key-after operate-map [do-occur]
  778. '(menu-item "List lines matching..." ibuffer-do-occur
  779. :help "View all lines in marked buffers matching a regexp"))
  780. (define-key-after operate-map [do-shell-command-pipe]
  781. '(menu-item "Pipe to shell command..." ibuffer-do-shell-command-pipe
  782. :help "For each marked buffer, send its contents to a shell command"))
  783. (define-key-after operate-map [do-shell-command-pipe-replace]
  784. '(menu-item "Pipe to shell command (replace)..." ibuffer-do-shell-command-pipe-replace
  785. :help "For each marked buffer, replace its contents with output of shell command"))
  786. (define-key-after operate-map [do-shell-command-file]
  787. '(menu-item "Shell command on buffer's file..." ibuffer-do-shell-command-file
  788. :help "For each marked buffer, run a shell command with its file as argument"))
  789. (define-key-after operate-map [do-eval]
  790. '(menu-item "Eval..." ibuffer-do-eval
  791. :help "Evaluate a Lisp form in each marked buffer"))
  792. (define-key-after operate-map [do-view-and-eval]
  793. '(menu-item "Eval (viewing buffer)..." ibuffer-do-view-and-eval
  794. :help "Evaluate a Lisp form in each marked buffer while viewing it"))
  795. (define-key-after operate-map [diff-with-file]
  796. '(menu-item "Diff with file" ibuffer-diff-with-file
  797. :help "View the differences between this buffer and its file"))
  798. operate-map))
  799. (define-key ibuffer-mode-groups-popup [kill-filter-group]
  800. '(menu-item "Kill filter group"
  801. ibuffer-kill-line
  802. :enable (and (featurep 'ibuf-ext)
  803. ibuffer-filter-groups)))
  804. (define-key ibuffer-mode-groups-popup [yank-filter-group]
  805. '(menu-item "Yank last killed filter group"
  806. ibuffer-yank
  807. :enable (and (featurep 'ibuf-ext)
  808. ibuffer-filter-group-kill-ring)))
  809. (defvar ibuffer-name-map
  810. (let ((map (make-sparse-keymap)))
  811. (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
  812. (define-key map [(mouse-2)] 'ibuffer-mouse-visit-buffer)
  813. (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
  814. map))
  815. (defvar ibuffer-filename/process-header-map
  816. (let ((map (make-sparse-keymap)))
  817. (define-key map [(mouse-1)] 'ibuffer-do-sort-by-filename/process)
  818. map))
  819. (defvar ibuffer-mode-name-map
  820. (let ((map (make-sparse-keymap)))
  821. (define-key map [(mouse-2)] 'ibuffer-mouse-filter-by-mode)
  822. (define-key map (kbd "RET") 'ibuffer-interactive-filter-by-mode)
  823. map))
  824. (defvar ibuffer-name-header-map
  825. (let ((map (make-sparse-keymap)))
  826. (define-key map [(mouse-1)] 'ibuffer-do-sort-by-alphabetic)
  827. map))
  828. (defvar ibuffer-size-header-map
  829. (let ((map (make-sparse-keymap)))
  830. (define-key map [(mouse-1)] 'ibuffer-do-sort-by-size)
  831. map))
  832. (defvar ibuffer-mode-header-map
  833. (let ((map (make-sparse-keymap)))
  834. (define-key map [(mouse-1)] 'ibuffer-do-sort-by-major-mode)
  835. map))
  836. (defvar ibuffer-mode-filter-group-map
  837. (let ((map (make-sparse-keymap)))
  838. (define-key map [(mouse-1)] 'ibuffer-mouse-toggle-mark)
  839. (define-key map [(mouse-2)] 'ibuffer-mouse-toggle-filter-group)
  840. (define-key map (kbd "RET") 'ibuffer-toggle-filter-group)
  841. (define-key map [down-mouse-3] 'ibuffer-mouse-popup-menu)
  842. map))
  843. (defvar ibuffer-did-modification nil)
  844. (defvar ibuffer-compiled-formats nil)
  845. (defvar ibuffer-cached-formats nil)
  846. (defvar ibuffer-cached-eliding-string nil)
  847. (defvar ibuffer-cached-elide-long-columns 0)
  848. (defvar ibuffer-sorting-functions-alist nil
  849. "An alist of functions which describe how to sort buffers.
  850. Note: You most likely do not want to modify this variable directly;
  851. use `define-ibuffer-sorter' instead.
  852. The alist elements are constructed like (NAME DESCRIPTION FUNCTION)
  853. Where NAME is a symbol describing the sorting method, DESCRIPTION is a
  854. short string which will be displayed in the minibuffer and menu, and
  855. FUNCTION is a function of two arguments, which will be the buffers to
  856. compare.")
  857. ;;; Utility functions
  858. (defun ibuffer-columnize-and-insert-list (list &optional pad-width)
  859. "Insert LIST into the current buffer in as many columns as possible.
  860. The maximum number of columns is determined by the current window
  861. width and the longest string in LIST."
  862. (unless pad-width
  863. (setq pad-width 3))
  864. (let ((width (window-width))
  865. (max (+ (apply #'max (mapcar #'length list))
  866. pad-width)))
  867. (let ((columns (/ width max)))
  868. (when (zerop columns)
  869. (setq columns 1))
  870. (while list
  871. (dotimes (_ (1- columns))
  872. (insert (concat (car list) (make-string (- max (length (car list)))
  873. ?\s)))
  874. (setq list (cdr list)))
  875. (when (not (null list))
  876. (insert (pop list)))
  877. (insert "\n")))))
  878. (defsubst ibuffer-current-mark ()
  879. (cadr (get-text-property (line-beginning-position)
  880. 'ibuffer-properties)))
  881. (defun ibuffer-mouse-toggle-mark (event)
  882. "Toggle the marked status of the buffer chosen with the mouse."
  883. (interactive "e")
  884. (unwind-protect
  885. (let ((pt (save-excursion
  886. (mouse-set-point event)
  887. (point))))
  888. (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
  889. (ibuffer-toggle-marks it)
  890. (goto-char pt)
  891. (let ((mark (ibuffer-current-mark)))
  892. (setq buffer-read-only nil)
  893. (if (eq mark ibuffer-marked-char)
  894. (ibuffer-set-mark ?\s)
  895. (ibuffer-set-mark ibuffer-marked-char)))))
  896. (setq buffer-read-only t)))
  897. (defun ibuffer-find-file (file &optional wildcards)
  898. "Like `find-file', but default to the directory of the buffer at point."
  899. (interactive
  900. (let ((default-directory (let ((buf (ibuffer-current-buffer)))
  901. (if (buffer-live-p buf)
  902. (with-current-buffer buf
  903. default-directory)
  904. default-directory))))
  905. (list (read-file-name "Find file: " default-directory)
  906. t)))
  907. (find-file file wildcards))
  908. (defun ibuffer-mouse-visit-buffer (event)
  909. "Visit the buffer chosen with the mouse."
  910. (interactive "e")
  911. (switch-to-buffer
  912. (save-excursion
  913. (mouse-set-point event)
  914. (ibuffer-current-buffer t))))
  915. (defun ibuffer-mouse-popup-menu (event)
  916. "Display a menu of operations."
  917. (interactive "e")
  918. (let ((eventpt (posn-point (event-end event)))
  919. (origpt (point)))
  920. (unwind-protect
  921. (if (get-text-property eventpt 'ibuffer-filter-group-name)
  922. (progn
  923. (goto-char eventpt)
  924. (popup-menu ibuffer-mode-groups-popup))
  925. (let ((inhibit-read-only t))
  926. (ibuffer-save-marks
  927. (ibuffer-unmark-all-marks)
  928. (save-excursion
  929. (goto-char eventpt)
  930. (ibuffer-set-mark ibuffer-marked-char))
  931. (save-excursion
  932. (popup-menu ibuffer-mode-operate-map)))))
  933. (setq buffer-read-only t)
  934. (if (= eventpt (point))
  935. (goto-char origpt)))))
  936. (defun ibuffer-skip-properties (props direction)
  937. (while (and (not (eobp))
  938. (let ((hit nil))
  939. (dolist (prop props hit)
  940. (when (get-text-property (point) prop)
  941. (setq hit t)))))
  942. (forward-line direction)
  943. (beginning-of-line)))
  944. (defun ibuffer-customize ()
  945. "Begin customizing Ibuffer interactively."
  946. (interactive)
  947. (customize-group 'ibuffer))
  948. (defun ibuffer-backward-line (&optional arg skip-group-names)
  949. "Move backwards ARG lines, wrapping around the list if necessary."
  950. (interactive "P")
  951. (or arg (setq arg 1))
  952. (beginning-of-line)
  953. (while (> arg 0)
  954. (forward-line -1)
  955. (when (and ibuffer-movement-cycle
  956. (or (get-text-property (point) 'ibuffer-title)
  957. (and skip-group-names
  958. (get-text-property (point)
  959. 'ibuffer-filter-group-name))))
  960. (goto-char (point-max))
  961. (beginning-of-line))
  962. (ibuffer-skip-properties (append '(ibuffer-summary)
  963. (when skip-group-names
  964. '(ibuffer-filter-group-name)))
  965. -1)
  966. ;; Handle the special case of no buffers.
  967. (when (get-text-property (point) 'ibuffer-title)
  968. (forward-line 1)
  969. (setq arg 1))
  970. (cl-decf arg)))
  971. (defun ibuffer-forward-line (&optional arg skip-group-names)
  972. "Move forward ARG lines, wrapping around the list if necessary."
  973. (interactive "P")
  974. (or arg (setq arg 1))
  975. (beginning-of-line)
  976. (when (and ibuffer-movement-cycle
  977. (or (eobp)
  978. (get-text-property (point) 'ibuffer-summary)))
  979. (goto-char (point-min)))
  980. (when (or (get-text-property (point) 'ibuffer-title)
  981. (and skip-group-names
  982. (get-text-property (point) 'ibuffer-filter-group-name)))
  983. (when (> arg 0)
  984. (cl-decf arg))
  985. (ibuffer-skip-properties (append '(ibuffer-title)
  986. (when skip-group-names
  987. '(ibuffer-filter-group-name)))
  988. 1))
  989. (if (< arg 0)
  990. (ibuffer-backward-line (- arg))
  991. (while (> arg 0)
  992. (forward-line 1)
  993. (when (and ibuffer-movement-cycle
  994. (or (eobp)
  995. (get-text-property (point) 'ibuffer-summary)))
  996. (goto-char (point-min)))
  997. (cl-decf arg)
  998. (ibuffer-skip-properties (append '(ibuffer-title)
  999. (when skip-group-names
  1000. '(ibuffer-filter-group-name)))
  1001. 1))))
  1002. (defun ibuffer-visit-buffer (&optional single)
  1003. "Visit the buffer on this line.
  1004. If optional argument SINGLE is non-nil, then also ensure there is only
  1005. one window."
  1006. (interactive "P")
  1007. (let ((buf (ibuffer-current-buffer t)))
  1008. (switch-to-buffer buf)
  1009. (when single
  1010. (delete-other-windows))))
  1011. (defun ibuffer-visit-buffer-other-window (&optional noselect)
  1012. "Visit the buffer on this line in another window."
  1013. (interactive)
  1014. (let ((buf (ibuffer-current-buffer t)))
  1015. (bury-buffer (current-buffer))
  1016. (if noselect
  1017. (let ((curwin (selected-window)))
  1018. (pop-to-buffer buf)
  1019. (select-window curwin))
  1020. (switch-to-buffer-other-window buf))))
  1021. (defun ibuffer-visit-buffer-other-window-noselect ()
  1022. "Visit the buffer on this line in another window, but don't select it."
  1023. (interactive)
  1024. (ibuffer-visit-buffer-other-window t))
  1025. (defun ibuffer-visit-buffer-other-frame ()
  1026. "Visit the buffer on this line in another frame."
  1027. (interactive)
  1028. (let ((buf (ibuffer-current-buffer t)))
  1029. (bury-buffer (current-buffer))
  1030. (switch-to-buffer-other-frame buf)))
  1031. (defun ibuffer-visit-buffer-1-window ()
  1032. "Visit the buffer on this line, and delete other windows."
  1033. (interactive)
  1034. (ibuffer-visit-buffer t))
  1035. (defun ibuffer-bury-buffer ()
  1036. "Bury the buffer on this line."
  1037. (interactive)
  1038. (let ((buf (ibuffer-current-buffer t))
  1039. (line (+ 1 (count-lines 1 (point)))))
  1040. (bury-buffer buf)
  1041. (ibuffer-update nil t)
  1042. (goto-char (point-min))
  1043. (forward-line (1- line))))
  1044. (defun ibuffer-visit-tags-table ()
  1045. "Visit the tags table in the buffer on this line. See `visit-tags-table'."
  1046. (interactive)
  1047. (let ((file (buffer-file-name (ibuffer-current-buffer t))))
  1048. (if file
  1049. (visit-tags-table file)
  1050. (error "Specified buffer has no file"))))
  1051. (defun ibuffer-do-view (&optional other-frame)
  1052. "View marked buffers, or the buffer on the current line.
  1053. If optional argument OTHER-FRAME is non-nil, then display each
  1054. marked buffer in a new frame. Otherwise, display each buffer as
  1055. a new window in the current frame, splitting vertically."
  1056. (interactive)
  1057. (ibuffer-do-view-1 (if other-frame 'other-frame 'vertically)))
  1058. (defun ibuffer-do-view-horizontally (&optional other-frame)
  1059. "As `ibuffer-do-view', but split windows horizontally."
  1060. (interactive)
  1061. (ibuffer-do-view-1 (if other-frame 'other-frame 'horizontally)))
  1062. (defun ibuffer-do-view-1 (type)
  1063. (let ((marked-bufs (or (ibuffer-get-marked-buffers)
  1064. (list (ibuffer-current-buffer t)))))
  1065. (unless (and (eq type 'other-frame)
  1066. (not ibuffer-expert)
  1067. (> (length marked-bufs) 3)
  1068. (not (y-or-n-p (format "Really create a new frame for %s buffers? "
  1069. (length marked-bufs)))))
  1070. (unless (eq type 'other-frame)
  1071. (set-buffer-modified-p nil)
  1072. (delete-other-windows)
  1073. (switch-to-buffer (pop marked-bufs)))
  1074. (let ((height (/ (1- (if (eq type 'horizontally) (frame-width)
  1075. (frame-height)))
  1076. (1+ (length marked-bufs)))))
  1077. (mapcar (if (eq type 'other-frame)
  1078. (lambda (buf)
  1079. (let ((curframe (selected-frame)))
  1080. (select-frame (make-frame))
  1081. (switch-to-buffer buf)
  1082. (select-frame curframe)))
  1083. (lambda (buf)
  1084. (split-window nil height (eq type 'horizontally))
  1085. (other-window 1)
  1086. (switch-to-buffer buf)))
  1087. marked-bufs)))))
  1088. (defun ibuffer-do-view-other-frame ()
  1089. "View each of the marked buffers in a separate frame."
  1090. (interactive)
  1091. (ibuffer-do-view t))
  1092. (defsubst ibuffer-map-marked-lines (func)
  1093. (prog1 (ibuffer-map-on-mark ibuffer-marked-char func)
  1094. (ibuffer-redisplay t)))
  1095. (defun ibuffer-shrink-to-fit (&optional owin)
  1096. ;; Make sure that redisplay is performed, otherwise there can be a
  1097. ;; bad interaction with code in the window-scroll-functions hook
  1098. (redisplay t)
  1099. (fit-window-to-buffer nil (when owin (/ (frame-height)
  1100. (length (window-list (selected-frame)))))))
  1101. (defun ibuffer-confirm-operation-on (operation names)
  1102. "Display a buffer asking whether to perform OPERATION on NAMES."
  1103. (or ibuffer-expert
  1104. (if (= (length names) 1)
  1105. (y-or-n-p (format "Really %s buffer %s? " operation (car names)))
  1106. (let ((buf (get-buffer-create "*Ibuffer confirmation*")))
  1107. (with-current-buffer buf
  1108. (setq buffer-read-only nil)
  1109. (erase-buffer)
  1110. (ibuffer-columnize-and-insert-list names)
  1111. (goto-char (point-min))
  1112. (setq buffer-read-only t))
  1113. (let ((windows (nreverse (window-list nil 'nomini)))
  1114. lastwin)
  1115. (while (window-parameter (car windows) 'window-side)
  1116. (setq windows (cdr windows)))
  1117. (setq lastwin (car windows))
  1118. ;; Now attempt to display the buffer...
  1119. (save-window-excursion
  1120. (select-window lastwin)
  1121. ;; The window might be too small to split; in that case,
  1122. ;; try a few times to increase its size before giving up.
  1123. (let ((attempts 0)
  1124. (trying t))
  1125. (while trying
  1126. (condition-case err
  1127. (progn
  1128. (split-window)
  1129. (setq trying nil))
  1130. (error
  1131. ;; Handle a failure
  1132. (if (or (> (cl-incf attempts) 4)
  1133. (and (stringp (cadr err))
  1134. ;; This definitely falls in the
  1135. ;; ghetto hack category...
  1136. (not (string-match-p "too small" (cadr err)))))
  1137. (signal (car err) (cdr err))
  1138. (enlarge-window 3))))))
  1139. (select-window (next-window))
  1140. (switch-to-buffer buf)
  1141. (unwind-protect
  1142. (progn
  1143. (fit-window-to-buffer)
  1144. (y-or-n-p (format "Really %s %d buffers? "
  1145. operation (length names))))
  1146. (kill-buffer buf))))))))
  1147. (defsubst ibuffer-map-lines-nomodify (function)
  1148. "As `ibuffer-map-lines', but don't set the modification flag."
  1149. (ibuffer-map-lines function t))
  1150. (defun ibuffer-buffer-names-with-mark (mark)
  1151. (let ((ibuffer-buffer-names-with-mark-result nil))
  1152. (ibuffer-map-lines-nomodify
  1153. (lambda (buf mk)
  1154. (when (eq mark mk)
  1155. (push (buffer-name buf)
  1156. ibuffer-buffer-names-with-mark-result))))
  1157. ibuffer-buffer-names-with-mark-result))
  1158. (defsubst ibuffer-marked-buffer-names ()
  1159. (ibuffer-buffer-names-with-mark ibuffer-marked-char))
  1160. (defsubst ibuffer-deletion-marked-buffer-names ()
  1161. (ibuffer-buffer-names-with-mark ibuffer-deletion-char))
  1162. (defun ibuffer-count-marked-lines (&optional all)
  1163. (if all
  1164. (ibuffer-map-lines-nomodify
  1165. (lambda (_buf mark)
  1166. (not (eq mark ?\s))))
  1167. (ibuffer-map-lines-nomodify
  1168. (lambda (_buf mark)
  1169. (eq mark ibuffer-marked-char)))))
  1170. (defsubst ibuffer-count-deletion-lines ()
  1171. (ibuffer-map-lines-nomodify
  1172. (lambda (_buf mark)
  1173. (eq mark ibuffer-deletion-char))))
  1174. (defsubst ibuffer-map-deletion-lines (func)
  1175. (ibuffer-map-on-mark ibuffer-deletion-char func))
  1176. (defsubst ibuffer-assert-ibuffer-mode ()
  1177. (cl-assert (derived-mode-p 'ibuffer-mode)))
  1178. (defun ibuffer-buffer-file-name ()
  1179. (cond
  1180. ((buffer-file-name))
  1181. ((bound-and-true-p list-buffers-directory))
  1182. ((let ((dirname (and (boundp 'dired-directory)
  1183. (if (stringp dired-directory)
  1184. dired-directory
  1185. (car dired-directory)))))
  1186. (and dirname (expand-file-name dirname))))))
  1187. (define-ibuffer-op ibuffer-do-save ()
  1188. "Save marked buffers as with `save-buffer'."
  1189. (:complex t
  1190. :opstring "saved"
  1191. :modifier-p :maybe)
  1192. (when (buffer-modified-p buf)
  1193. (if (not (with-current-buffer buf
  1194. buffer-file-name))
  1195. ;; handle the case where we're prompted
  1196. ;; for a file name
  1197. (save-window-excursion
  1198. (switch-to-buffer buf)
  1199. (save-buffer))
  1200. (with-current-buffer buf
  1201. (save-buffer))))
  1202. t)
  1203. (define-ibuffer-op ibuffer-do-toggle-modified ()
  1204. "Toggle modification flag of marked buffers."
  1205. (:opstring "(un)marked as modified"
  1206. :modifier-p t)
  1207. (set-buffer-modified-p (not (buffer-modified-p))))
  1208. (define-ibuffer-op ibuffer-do-toggle-read-only (&optional arg)
  1209. "Toggle read only status in marked buffers.
  1210. If optional ARG is a non-negative integer, make buffers read only.
  1211. If ARG is a negative integer or 0, make buffers writable.
  1212. Otherwise, toggle read only status."
  1213. (:opstring "toggled read only status in"
  1214. :interactive "P"
  1215. :modifier-p t)
  1216. (read-only-mode (if (integerp arg) arg 'toggle)))
  1217. (define-ibuffer-op ibuffer-do-delete ()
  1218. "Kill marked buffers as with `kill-this-buffer'."
  1219. (:opstring "killed"
  1220. :active-opstring "kill"
  1221. :dangerous t
  1222. :complex t
  1223. :modifier-p t)
  1224. (if (kill-buffer buf)
  1225. 'kill
  1226. nil))
  1227. (define-ibuffer-op ibuffer-do-kill-on-deletion-marks ()
  1228. "Kill buffers marked for deletion as with `kill-this-buffer'."
  1229. (:opstring "killed"
  1230. :active-opstring "kill"
  1231. :dangerous t
  1232. :complex t
  1233. :mark :deletion
  1234. :modifier-p t)
  1235. (if (kill-buffer buf)
  1236. 'kill
  1237. nil))
  1238. (defun ibuffer-unmark-all (mark)
  1239. "Unmark all buffers with mark MARK."
  1240. (interactive "cRemove marks (RET means all):")
  1241. (if (= (ibuffer-count-marked-lines t) 0)
  1242. (message "No buffers marked; use 'm' to mark a buffer")
  1243. (let ((fn (lambda (_buf mk)
  1244. (unless (eq mk ?\s)
  1245. (ibuffer-set-mark-1 ?\s)) t)))
  1246. (if (eq mark ?\r)
  1247. (ibuffer-map-lines fn)
  1248. (ibuffer-map-on-mark mark fn))))
  1249. (ibuffer-redisplay t))
  1250. (defun ibuffer-unmark-all-marks ()
  1251. "Remove all marks from all marked buffers in Ibuffer."
  1252. (interactive)
  1253. ;; hm. we could probably do this in a better fashion
  1254. (ibuffer-unmark-all ?\r))
  1255. (defun ibuffer-toggle-marks (&optional group)
  1256. "Toggle which buffers are marked.
  1257. In other words, unmarked buffers become marked, and marked buffers
  1258. become unmarked.
  1259. If point is on a group name, then this function operates on that
  1260. group."
  1261. (interactive)
  1262. (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
  1263. (setq group it))
  1264. (let ((count
  1265. (ibuffer-map-lines
  1266. (lambda (_buf mark)
  1267. (cond ((eq mark ibuffer-marked-char)
  1268. (ibuffer-set-mark-1 ?\s)
  1269. nil)
  1270. ((eq mark ?\s)
  1271. (ibuffer-set-mark-1 ibuffer-marked-char)
  1272. t)
  1273. (t
  1274. nil)))
  1275. nil group)))
  1276. (message "%s buffers marked" count))
  1277. (ibuffer-redisplay t))
  1278. (defun ibuffer-change-marks (&optional old new)
  1279. "Change all OLD marks to NEW marks.
  1280. OLD and NEW are both characters used to mark buffers."
  1281. (interactive
  1282. (let* ((cursor-in-echo-area t)
  1283. (old (progn (message "Change (old mark): ") (read-char)))
  1284. (new (progn (message "Change %c marks to (new mark): " old)
  1285. (read-char))))
  1286. (list old new)))
  1287. (if (or (eq old ?\r) (eq new ?\r))
  1288. (ding)
  1289. (let ((count
  1290. (ibuffer-map-lines
  1291. (lambda (_buf mark)
  1292. (when (eq mark old)
  1293. (ibuffer-set-mark new) t)))))
  1294. (message "%s marks changed" count))))
  1295. (defsubst ibuffer-get-region-and-prefix ()
  1296. (let ((arg (prefix-numeric-value current-prefix-arg)))
  1297. (if (use-region-p) (list (region-beginning) (region-end) arg)
  1298. (list nil nil arg))))
  1299. (defun ibuffer-mark-forward (start end arg)
  1300. "Mark the buffers in the region, or ARG buffers.
  1301. If point is on a group name, this function operates on that group."
  1302. (interactive (ibuffer-get-region-and-prefix))
  1303. (ibuffer-mark-region-or-n-with-char start end arg ibuffer-marked-char))
  1304. (defun ibuffer-unmark-forward (start end arg)
  1305. "Unmark the buffers in the region, or ARG buffers.
  1306. If point is on a group name, this function operates on that group."
  1307. (interactive (ibuffer-get-region-and-prefix))
  1308. (ibuffer-mark-region-or-n-with-char start end arg ?\s))
  1309. (defun ibuffer-unmark-backward (start end arg)
  1310. "Unmark the buffers in the region, or previous ARG buffers.
  1311. If point is on a group name, this function operates on that group."
  1312. (interactive (ibuffer-get-region-and-prefix))
  1313. (ibuffer-unmark-forward start end (- arg)))
  1314. (defun ibuffer-mark-region-or-n-with-char (start end arg mark-char)
  1315. (if (use-region-p)
  1316. (let ((cur (point)) (line-count (count-lines start end)))
  1317. (goto-char start)
  1318. (ibuffer-mark-interactive line-count mark-char)
  1319. (goto-char cur))
  1320. (ibuffer-mark-interactive arg mark-char)))
  1321. (defun ibuffer-mark-interactive (arg mark &optional movement)
  1322. (ibuffer-assert-ibuffer-mode)
  1323. (or arg (setq arg 1))
  1324. ;; deprecated movement argument
  1325. (when (and movement (< movement 0))
  1326. (setq arg (- arg)))
  1327. (ibuffer-forward-line 0)
  1328. (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group-name)
  1329. (progn
  1330. (require 'ibuf-ext)
  1331. (ibuffer-mark-on-buffer #'identity mark it))
  1332. (ibuffer-forward-line 0 t)
  1333. (while (> arg 0)
  1334. (ibuffer-set-mark mark)
  1335. (ibuffer-forward-line 1 t)
  1336. (setq arg (1- arg)))
  1337. (while (< arg 0)
  1338. (ibuffer-forward-line -1 t)
  1339. (ibuffer-set-mark mark)
  1340. (setq arg (1+ arg)))))
  1341. (defun ibuffer-set-mark (mark)
  1342. (ibuffer-assert-ibuffer-mode)
  1343. (let ((inhibit-read-only t))
  1344. (ibuffer-set-mark-1 mark)
  1345. (setq ibuffer-did-modification t)
  1346. (ibuffer-redisplay-current)
  1347. (beginning-of-line)))
  1348. (defun ibuffer-set-mark-1 (mark)
  1349. (let ((beg (line-beginning-position))
  1350. (end (line-end-position)))
  1351. (put-text-property beg end 'ibuffer-properties
  1352. (list (ibuffer-current-buffer)
  1353. mark))))
  1354. (defun ibuffer-mark-for-delete (start end arg)
  1355. "Mark for deletion the buffers in the region, or ARG buffers.
  1356. If point is on a group name, this function operates on that group."
  1357. (interactive (ibuffer-get-region-and-prefix))
  1358. (ibuffer-mark-region-or-n-with-char start end arg ibuffer-deletion-char))
  1359. (defun ibuffer-mark-for-delete-backwards (arg)
  1360. "Mark for deletion the ARG previous buffers.
  1361. If point is on a group name, this function operates on that group."
  1362. (interactive "p")
  1363. (ibuffer-mark-interactive arg ibuffer-deletion-char -1))
  1364. (defun ibuffer-current-buffer (&optional must-be-live)
  1365. (let ((buf (car (get-text-property (line-beginning-position)
  1366. 'ibuffer-properties))))
  1367. (when must-be-live
  1368. (if (bufferp buf)
  1369. (unless (buffer-live-p buf)
  1370. (error "Buffer %s has been killed; %s" buf (substitute-command-keys "use `\\[ibuffer-update]' to update")))
  1371. (error "No buffer on this line")))
  1372. buf))
  1373. (defun ibuffer-active-formats-name ()
  1374. (if (boundp 'ibuffer-filter-format-alist)
  1375. (let ((ret nil))
  1376. (dolist (filter ibuffer-filtering-qualifiers ret)
  1377. (let ((val (assq (car filter) ibuffer-filter-format-alist)))
  1378. (when val
  1379. (setq ret (car filter)))))
  1380. (if ret
  1381. ret
  1382. :ibuffer-formats))
  1383. :ibuffer-formats))
  1384. (defun ibuffer-current-formats (uncompiledp)
  1385. (let* ((name (ibuffer-active-formats-name)))
  1386. (ibuffer-check-formats)
  1387. (if (eq name :ibuffer-formats)
  1388. (if uncompiledp
  1389. ibuffer-formats
  1390. ibuffer-compiled-formats)
  1391. (cadr (assq name
  1392. (if uncompiledp
  1393. ibuffer-filter-format-alist
  1394. ibuffer-compiled-filter-formats))))))
  1395. (defun ibuffer-current-format (&optional uncompiledp)
  1396. (or ibuffer-current-format
  1397. (setq ibuffer-current-format 0))
  1398. (nth ibuffer-current-format (ibuffer-current-formats uncompiledp)))
  1399. (defun ibuffer-expand-format-entry (form)
  1400. (if (or (consp form)
  1401. (symbolp form))
  1402. (let ((sym (intern (concat "ibuffer-make-column-"
  1403. (symbol-name (if (consp form)
  1404. (car form)
  1405. form))))))
  1406. (unless (or (fboundp sym)
  1407. (assq sym ibuffer-inline-columns))
  1408. (error "Unknown column %s in ibuffer-formats" form))
  1409. (let (min max align elide)
  1410. (if (consp form)
  1411. (setq min (or (nth 1 form) 0)
  1412. max (or (nth 2 form) -1)
  1413. align (or (nth 3 form) :left)
  1414. elide (or (nth 4 form) nil))
  1415. (setq min 0
  1416. max -1
  1417. align :left
  1418. elide nil))
  1419. (list sym min max align elide)))
  1420. form))
  1421. (defun ibuffer-compile-make-eliding-form (strvar elide from-end-p)
  1422. (let ((ellipsis (propertize ibuffer-eliding-string 'font-lock-face 'bold)))
  1423. (if (or elide (with-no-warnings ibuffer-elide-long-columns))
  1424. `(if (> strlen 5)
  1425. ,(if from-end-p
  1426. ;; FIXME: this should probably also be using
  1427. ;; `truncate-string-to-width' (Bug#24972)
  1428. `(concat ,ellipsis
  1429. (substring ,strvar
  1430. (string-width ibuffer-eliding-string)))
  1431. `(concat
  1432. (truncate-string-to-width
  1433. ,strvar (- strlen (string-width ,ellipsis)) nil ?.)
  1434. ,ellipsis))
  1435. ,strvar)
  1436. strvar)))
  1437. (defun ibuffer-compile-make-substring-form (strvar maxvar from-end-p)
  1438. (if from-end-p
  1439. ;; FIXME: not sure if this case is correct (Bug#24972)
  1440. `(truncate-string-to-width str strlen (- strlen ,maxvar) nil ?\s)
  1441. `(truncate-string-to-width ,strvar ,maxvar nil ?\s)))
  1442. (defun ibuffer-compile-make-format-form (strvar widthform alignment)
  1443. (let* ((left `(make-string tmp2 ?\s))
  1444. (right `(make-string (- tmp1 tmp2) ?\s)))
  1445. `(progn
  1446. (setq tmp1 ,widthform
  1447. tmp2 (/ tmp1 2))
  1448. ,(pcase alignment
  1449. (:right `(concat ,left ,right ,strvar))
  1450. (:center `(concat ,left ,strvar ,right))
  1451. (:left `(concat ,strvar ,left ,right))
  1452. (_ (error "Invalid alignment %s" alignment))))))
  1453. (defun ibuffer-compile-format (format)
  1454. (let ((result nil)
  1455. ;; We use these variables to keep track of which variables
  1456. ;; inside the generated function we need to bind, since
  1457. ;; binding variables in Emacs takes time.
  1458. (vars-used ()))
  1459. (dolist (form format)
  1460. (push
  1461. ;; Generate a form based on a particular format entry, like
  1462. ;; " ", mark, or (mode 16 16 :right).
  1463. (if (stringp form)
  1464. ;; It's a string; all we need to do is insert it.
  1465. `(insert ,form)
  1466. (let* ((form (ibuffer-expand-format-entry form))
  1467. (sym (nth 0 form))
  1468. (min (nth 1 form))
  1469. (max (nth 2 form))
  1470. (align (nth 3 form))
  1471. (elide (nth 4 form)))
  1472. (let* ((from-end-p (when (cl-minusp min)
  1473. (setq min (- min))
  1474. t))
  1475. (letbindings nil)
  1476. (outforms nil)
  1477. minform
  1478. maxform
  1479. min-used max-used strlen-used)
  1480. (when (or (not (integerp min)) (>= min 0))
  1481. ;; This is a complex case; they want it limited to a
  1482. ;; minimum size.
  1483. (setq min-used t)
  1484. (setq strlen-used t)
  1485. (setq vars-used '(str strlen tmp1 tmp2))
  1486. ;; Generate code to limit the string to a minimum size.
  1487. (setq minform `(progn
  1488. (setq str
  1489. ,(ibuffer-compile-make-format-form
  1490. 'str
  1491. `(- ,(if (integerp min)
  1492. min
  1493. 'min)
  1494. strlen)
  1495. align)))))
  1496. (when (or (not (integerp max)) (> max 0))
  1497. (setq max-used t)
  1498. (cl-pushnew 'str vars-used)
  1499. ;; Generate code to limit the string to a maximum size.
  1500. (setq maxform `(progn
  1501. (setq str
  1502. ,(ibuffer-compile-make-substring-form
  1503. 'str
  1504. (if (integerp max)
  1505. max
  1506. 'max)
  1507. from-end-p))
  1508. (setq strlen (string-width str))
  1509. (setq str
  1510. ,(ibuffer-compile-make-eliding-form
  1511. 'str elide from-end-p)))))
  1512. ;; Now, put these forms together with the rest of the code.
  1513. (let ((callform
  1514. ;; Is this an "inline" column? This means we have
  1515. ;; to get the code from the
  1516. ;; `ibuffer-inline-columns' alist and insert it
  1517. ;; into our generated code. Otherwise, we just
  1518. ;; generate a call to the column function.
  1519. (ibuffer-aif (assq sym ibuffer-inline-columns)
  1520. (nth 1 it)
  1521. `(or (,sym buffer mark) "")))
  1522. ;; You're not expected to understand this. Hell, I
  1523. ;; don't even understand it, and I wrote it five
  1524. ;; minutes ago.
  1525. (insertgenfn
  1526. (if (get sym 'ibuffer-column-summarizer)
  1527. ;; I really, really wish Emacs Lisp had closures.
  1528. ;; FIXME: Elisp does have them now.
  1529. (lambda (arg sym)
  1530. `(insert
  1531. (let ((ret ,arg))
  1532. (put ',sym 'ibuffer-column-summary
  1533. (cons ret (get ',sym
  1534. 'ibuffer-column-summary)))
  1535. ret)))
  1536. (lambda (arg _sym)
  1537. `(insert ,arg))))
  1538. (mincompform `(< strlen ,(if (integerp min)
  1539. min
  1540. 'min)))
  1541. (maxcompform `(> strlen ,(if (integerp max)
  1542. max
  1543. 'max))))
  1544. (if (or min-used max-used)
  1545. ;; The complex case, where we have to limit the
  1546. ;; form to a maximum or minimum size.
  1547. (progn
  1548. (when (and min-used (not (integerp min)))
  1549. (push `(min ,min) letbindings))
  1550. (when (and max-used (not (integerp max)))
  1551. (push `(max ,max) letbindings))
  1552. (push
  1553. (if (and min-used max-used)
  1554. `(if ,mincompform
  1555. ,minform
  1556. (if ,maxcompform
  1557. ,maxform))
  1558. (if min-used
  1559. `(when ,mincompform
  1560. ,minform)
  1561. `(when ,maxcompform
  1562. ,maxform)))
  1563. outforms)
  1564. (push `(setq str ,callform
  1565. ,@(when strlen-used
  1566. `(strlen (string-width str))))
  1567. outforms)
  1568. (setq outforms
  1569. (append outforms
  1570. (list (funcall insertgenfn 'str sym)))))
  1571. ;; The simple case; just insert the string.
  1572. (push (funcall insertgenfn callform sym) outforms))
  1573. ;; Finally, return a `let' form which binds the
  1574. ;; variables in `letbindings', and contains all the
  1575. ;; code in `outforms'.
  1576. `(let ,letbindings
  1577. ,@outforms)))))
  1578. result))
  1579. ;; We don't want to unconditionally load the byte-compiler.
  1580. (funcall (if (or ibuffer-always-compile-formats
  1581. (featurep 'bytecomp))
  1582. #'byte-compile
  1583. #'identity)
  1584. ;; Here, we actually create a lambda form which
  1585. ;; inserts all the generated forms for each entry
  1586. ;; in the format string.
  1587. `(lambda (buffer mark)
  1588. (let ,vars-used
  1589. ,@(nreverse result))))))
  1590. (defun ibuffer-recompile-formats ()
  1591. "Recompile `ibuffer-formats'."
  1592. (interactive)
  1593. (setq ibuffer-compiled-formats
  1594. (mapcar #'ibuffer-compile-format ibuffer-formats))
  1595. (when (boundp 'ibuffer-filter-format-alist)
  1596. (setq ibuffer-compiled-filter-formats
  1597. (mapcar (lambda (entry)
  1598. (cons (car entry)
  1599. (mapcar (lambda (formats)
  1600. (mapcar #'ibuffer-compile-format formats))
  1601. (cdr entry))))
  1602. ibuffer-filter-format-alist))))
  1603. (defun ibuffer-clear-summary-columns (format)
  1604. (dolist (form format)
  1605. (when (and (consp form)
  1606. (get (car form) 'ibuffer-column-summarizer))
  1607. (put (car form) 'ibuffer-column-summary nil))))
  1608. (defun ibuffer-check-formats ()
  1609. (when (null ibuffer-formats)
  1610. (error "No formats!"))
  1611. (let ((ext-loaded (featurep 'ibuf-ext)))
  1612. (when (or (null ibuffer-compiled-formats)
  1613. (null ibuffer-cached-formats)
  1614. (not (eq ibuffer-cached-formats ibuffer-formats))
  1615. (null ibuffer-cached-eliding-string)
  1616. (not (equal ibuffer-cached-eliding-string ibuffer-eliding-string))
  1617. (eql 0 ibuffer-cached-elide-long-columns)
  1618. (not (eql ibuffer-cached-elide-long-columns
  1619. (with-no-warnings ibuffer-elide-long-columns)))
  1620. (and ext-loaded
  1621. (not (eq ibuffer-cached-filter-formats
  1622. ibuffer-filter-format-alist))
  1623. (and ibuffer-filter-format-alist
  1624. (null ibuffer-compiled-filter-formats))))
  1625. (message "Formats have changed, recompiling...")
  1626. (ibuffer-recompile-formats)
  1627. (setq ibuffer-cached-formats ibuffer-formats
  1628. ibuffer-cached-eliding-string ibuffer-eliding-string
  1629. ibuffer-cached-elide-long-columns (with-no-warnings ibuffer-elide-long-columns))
  1630. (when ext-loaded
  1631. (setq ibuffer-cached-filter-formats ibuffer-filter-format-alist))
  1632. (message "Formats have changed, recompiling...done"))))
  1633. (defvar ibuffer-inline-columns nil)
  1634. (defface ibuffer-locked-buffer
  1635. '((((background dark)) (:foreground "RosyBrown"))
  1636. (t (:foreground "brown4")))
  1637. "*Face used for locked buffers in Ibuffer."
  1638. :version "26.1"
  1639. :group 'ibuffer
  1640. :group 'font-lock-highlighting-faces)
  1641. (defvar ibuffer-locked-buffer 'ibuffer-locked-buffer)
  1642. (define-ibuffer-column mark (:name " " :inline t)
  1643. (string mark))
  1644. (define-ibuffer-column read-only (:name "R" :inline t)
  1645. (if buffer-read-only
  1646. (string ibuffer-read-only-char)
  1647. " "))
  1648. (define-ibuffer-column locked
  1649. (:name "L" :inline t :props ('font-lock-face 'ibuffer-locked-buffer))
  1650. (if (and (boundp 'emacs-lock-mode) emacs-lock-mode)
  1651. (string ibuffer-locked-char)
  1652. " "))
  1653. (define-ibuffer-column modified (:name "M" :inline t)
  1654. (if (buffer-modified-p)
  1655. (string ibuffer-modified-char)
  1656. " "))
  1657. (define-ibuffer-column name
  1658. (:inline t
  1659. :header-mouse-map ibuffer-name-header-map
  1660. :props
  1661. ('mouse-face 'highlight 'keymap ibuffer-name-map
  1662. 'ibuffer-name-column t
  1663. 'help-echo '(if tooltip-mode
  1664. "mouse-1: mark this buffer\nmouse-2: select this buffer\nmouse-3: operate on this buffer"
  1665. "mouse-1: mark buffer mouse-2: select buffer mouse-3: operate"))
  1666. :summarizer
  1667. (lambda (strings)
  1668. (let ((bufs (length strings)))
  1669. (cond ((zerop bufs) "No buffers")
  1670. ((= 1 bufs) "1 buffer")
  1671. (t (format "%s buffers" bufs))))))
  1672. (let ((string (propertize (buffer-name)
  1673. 'font-lock-face
  1674. (ibuffer-buffer-name-face buffer mark))))
  1675. (if (not (seq-position string ?\n))
  1676. string
  1677. (replace-regexp-in-string
  1678. "\n" (propertize "^J" 'font-lock-face 'escape-glyph) string))))
  1679. (define-ibuffer-column size
  1680. (:inline t
  1681. :header-mouse-map ibuffer-size-header-map
  1682. :summarizer
  1683. (lambda (column-strings)
  1684. (let ((total 0))
  1685. (dolist (string column-strings)
  1686. (setq total
  1687. ;; like, ewww ...
  1688. (+ (float (string-to-number string))
  1689. total)))
  1690. (format "%.0f" total))))
  1691. (format "%s" (buffer-size)))
  1692. (define-ibuffer-column mode
  1693. (:inline t
  1694. :header-mouse-map ibuffer-mode-header-map
  1695. :props
  1696. ('mouse-face 'highlight
  1697. 'keymap ibuffer-mode-name-map
  1698. 'help-echo "mouse-2: filter by this mode"))
  1699. (format-mode-line mode-name nil nil (current-buffer)))
  1700. (define-ibuffer-column process
  1701. (:summarizer
  1702. (lambda (strings)
  1703. (let ((total (length (delete "" strings))))
  1704. (cond ((zerop total) "No processes")
  1705. ((= 1 total) "1 process")
  1706. (t (format "%d processes" total))))))
  1707. (ibuffer-aif (get-buffer-process buffer)
  1708. (format "(%s %s)" it (process-status it))
  1709. ""))
  1710. (define-ibuffer-column filename
  1711. (:summarizer
  1712. (lambda (strings)
  1713. (let ((total (length (delete "" strings))))
  1714. (cond ((zerop total) "No files")
  1715. ((= 1 total) "1 file")
  1716. (t (format "%d files" total))))))
  1717. (let ((directory-abbrev-alist ibuffer-directory-abbrev-alist))
  1718. (abbreviate-file-name
  1719. (or (ibuffer-buffer-file-name) ""))))
  1720. (define-ibuffer-column filename-and-process
  1721. (:name "Filename/Process"
  1722. :header-mouse-map ibuffer-filename/process-header-map
  1723. :summarizer
  1724. (lambda (strings)
  1725. (setq strings (delete "" strings))
  1726. (let ((procs 0)
  1727. (files 0))
  1728. (dolist (string strings)
  1729. (if (string-match "\\(?:\\`([[:ascii:]]+)\\)" string)
  1730. (progn (setq procs (1+ procs))
  1731. (if (< (match-end 0) (length string))
  1732. (setq files (1+ files))))
  1733. (setq files (1+ files))))
  1734. (concat (cond ((zerop files) "No files")
  1735. ((= 1 files) "1 file")
  1736. (t (format "%d files" files)))
  1737. ", "
  1738. (cond ((zerop procs) "no processes")
  1739. ((= 1 procs) "1 process")
  1740. (t (format "%d processes" procs)))))))
  1741. (let ((proc (get-buffer-process buffer))
  1742. (filename (ibuffer-make-column-filename buffer mark)))
  1743. (if proc
  1744. (concat (propertize (format "(%s %s)" proc (process-status proc))
  1745. 'font-lock-face 'italic)
  1746. (if (> (length filename) 0)
  1747. (format " %s" filename)
  1748. ""))
  1749. filename)))
  1750. (defun ibuffer-format-column (str width alignment)
  1751. (let ((left (make-string (/ width 2) ?\s))
  1752. (right (make-string (- width (/ width 2)) ?\s)))
  1753. (pcase alignment
  1754. (:right (concat left right str))
  1755. (:center (concat left str right))
  1756. (_ (concat str left right)))))
  1757. (defun ibuffer-buffer-name-face (buf mark)
  1758. (cond ((eq mark ibuffer-marked-char)
  1759. ibuffer-marked-face)
  1760. ((eq mark ibuffer-deletion-char)
  1761. ibuffer-deletion-face)
  1762. (t
  1763. (let ((level -1)
  1764. result)
  1765. (dolist (e ibuffer-fontification-alist result)
  1766. (when (and (> (car e) level)
  1767. (with-current-buffer buf
  1768. (eval (nth 1 e))))
  1769. (setq level (car e)
  1770. result (nth 2 e))))))))
  1771. (defun ibuffer-insert-buffer-line (buffer mark format)
  1772. "Insert a line describing BUFFER and MARK using FORMAT."
  1773. (ibuffer-assert-ibuffer-mode)
  1774. (let ((beg (point)))
  1775. (funcall format buffer mark)
  1776. (put-text-property beg (point) 'ibuffer-properties (list buffer mark)))
  1777. (insert "\n"))
  1778. ;; This function knows a bit too much of the internals. It would be
  1779. ;; nice if it was all abstracted away.
  1780. (defun ibuffer-redisplay-current ()
  1781. (ibuffer-assert-ibuffer-mode)
  1782. (when (eobp)
  1783. (forward-line -1))
  1784. (beginning-of-line)
  1785. (let ((curformat (mapcar #'ibuffer-expand-format-entry
  1786. (ibuffer-current-format t))))
  1787. (ibuffer-clear-summary-columns curformat)
  1788. (let ((buf (ibuffer-current-buffer)))
  1789. (when buf
  1790. (let ((mark (ibuffer-current-mark)))
  1791. (save-excursion
  1792. (delete-region (point) (1+ (line-end-position)))
  1793. (ibuffer-insert-buffer-line
  1794. buf mark
  1795. (ibuffer-current-format)))
  1796. (when ibuffer-shrink-to-minimum-size
  1797. (ibuffer-shrink-to-fit)))))))
  1798. (defun ibuffer-map-on-mark (mark func)
  1799. (ibuffer-map-lines
  1800. (lambda (buf mk)
  1801. (if (eq mark mk)
  1802. (funcall func buf mark)
  1803. nil))))
  1804. (defun ibuffer-map-lines (function &optional nomodify group)
  1805. "Call FUNCTION for each buffer.
  1806. Set the ibuffer modification flag unless NOMODIFY is non-nil.
  1807. If optional argument GROUP is non-nil, then only call FUNCTION on
  1808. buffers in filtering group GROUP.
  1809. FUNCTION is called with two arguments:
  1810. the buffer object itself and the current mark symbol."
  1811. (ibuffer-assert-ibuffer-mode)
  1812. (ibuffer-forward-line 0)
  1813. (let* ((orig-target-line (1+ (count-lines (save-excursion
  1814. (goto-char (point-min))
  1815. (ibuffer-forward-line 0)
  1816. (point))
  1817. (point))))
  1818. (target-line-offset orig-target-line)
  1819. (ibuffer-map-lines-total 0)
  1820. (ibuffer-map-lines-count 0))
  1821. (unwind-protect
  1822. (progn
  1823. (setq buffer-read-only nil)
  1824. (goto-char (point-min))
  1825. (ibuffer-forward-line 0 t)
  1826. (while (and (not (eobp))
  1827. (not (get-text-property (point) 'ibuffer-summary))
  1828. (progn
  1829. (ibuffer-forward-line 0 t)
  1830. (and (not (eobp))
  1831. (not (get-text-property (point) 'ibuffer-summary)))))
  1832. (let ((result
  1833. (if (buffer-live-p (ibuffer-current-buffer))
  1834. (when (or (null group)
  1835. (ibuffer-aif (get-text-property (point) 'ibuffer-filter-group)
  1836. (equal group it)))
  1837. (save-excursion
  1838. (funcall function
  1839. (ibuffer-current-buffer)
  1840. (ibuffer-current-mark))))
  1841. ;; Kill the line if the buffer is dead
  1842. 'kill)))
  1843. ;; A given mapping function should return:
  1844. ;; nil if it chose not to affect the buffer
  1845. ;; `kill' means the remove line from the buffer list
  1846. ;; t otherwise
  1847. (cl-incf ibuffer-map-lines-total)
  1848. (cond ((null result)
  1849. (forward-line 1))
  1850. ((eq result 'kill)
  1851. (delete-region (line-beginning-position)
  1852. (1+ (line-end-position)))
  1853. (cl-incf ibuffer-map-lines-count)
  1854. (when (< ibuffer-map-lines-total
  1855. orig-target-line)
  1856. (cl-decf target-line-offset)))
  1857. (t
  1858. (cl-incf ibuffer-map-lines-count)
  1859. (forward-line 1)))))
  1860. ibuffer-map-lines-count)
  1861. (progn
  1862. (setq buffer-read-only t)
  1863. (unless nomodify
  1864. (set-buffer-modified-p nil))
  1865. (goto-char (point-min))
  1866. (ibuffer-forward-line 0)
  1867. (ibuffer-forward-line (1- target-line-offset))))))
  1868. ;; Return buffers around current line.
  1869. (defun ibuffer--near-buffers (n)
  1870. (delq nil
  1871. (mapcar
  1872. (lambda (x)
  1873. (car (get-text-property
  1874. (line-beginning-position (if (natnump n) x (- (1- x))))
  1875. 'ibuffer-properties)))
  1876. (number-sequence 1 (abs n)))))
  1877. (defun ibuffer-get-marked-buffers ()
  1878. "Return a list of buffer objects currently marked."
  1879. (delq nil
  1880. (mapcar (lambda (e)
  1881. (when (eq (cdr e) ibuffer-marked-char)
  1882. (car e)))
  1883. (ibuffer-current-state-list))))
  1884. (defun ibuffer-current-state-list (&optional pos)
  1885. "Return a list like (BUF . MARK) of all buffers in an ibuffer.
  1886. If POS is non-nil, return a list like (BUF MARK POINT), where POINT is
  1887. the value of point at the beginning of the line for that buffer."
  1888. (let ((ibuffer-current-state-list-tmp '()))
  1889. ;; ah, if only we had closures. I bet this will mysteriously
  1890. ;; break later. Don't blame me.
  1891. (if pos
  1892. (ibuffer-map-lines-nomodify
  1893. (lambda (buf mark)
  1894. (when (buffer-live-p buf)
  1895. (push (list buf mark (point)) ibuffer-current-state-list-tmp))))
  1896. (ibuffer-map-lines-nomodify
  1897. (lambda (buf mark)
  1898. (when (buffer-live-p buf)
  1899. (push (cons buf mark) ibuffer-current-state-list-tmp)))))
  1900. (nreverse ibuffer-current-state-list-tmp)))
  1901. (defun ibuffer-current-buffers-with-marks (curbufs)
  1902. "Return a list like (BUF . MARK) of all open buffers."
  1903. (let ((bufs (ibuffer-current-state-list)))
  1904. (mapcar (lambda (buf) (let ((e (assq buf bufs)))
  1905. (if e
  1906. e
  1907. (cons buf ?\s))))
  1908. curbufs)))
  1909. (defun ibuffer-buf-matches-predicates (buf predicates)
  1910. (let ((hit nil)
  1911. (name (buffer-name buf)))
  1912. (dolist (pred predicates)
  1913. (when (if (stringp pred)
  1914. (string-match pred name)
  1915. (funcall pred buf))
  1916. (setq hit t)))
  1917. hit))
  1918. (defun ibuffer-filter-buffers (ibuffer-buf last bmarklist all)
  1919. (let ((ext-loaded (featurep 'ibuf-ext)))
  1920. (delq nil
  1921. (mapcar
  1922. ;; element should be like (BUFFER . MARK)
  1923. (lambda (e)
  1924. (let* ((buf (car e)))
  1925. (when
  1926. ;; This takes precedence over anything else
  1927. (or (and ibuffer-always-show-last-buffer
  1928. (eq last buf))
  1929. (funcall (if ext-loaded
  1930. #'ibuffer-ext-visible-p
  1931. #'ibuffer-visible-p)
  1932. buf all ibuffer-buf))
  1933. e)))
  1934. bmarklist))))
  1935. (defun ibuffer-visible-p (buf all &optional ibuffer-buf)
  1936. (and (or all
  1937. (not
  1938. (ibuffer-buf-matches-predicates buf ibuffer-maybe-show-predicates)))
  1939. (or ibuffer-view-ibuffer
  1940. (and ibuffer-buf
  1941. (not (eq ibuffer-buf buf))))))
  1942. ;; This function is a special case; it's not defined by
  1943. ;; `define-ibuffer-sorter'.
  1944. (defun ibuffer-do-sort-by-recency ()
  1945. "Sort the buffers by last view time."
  1946. (interactive)
  1947. (setq ibuffer-sorting-mode 'recency)
  1948. (when (eq ibuffer-last-sorting-mode 'recency)
  1949. (setq ibuffer-sorting-reversep (not ibuffer-sorting-reversep)))
  1950. (ibuffer-update nil t)
  1951. (setq ibuffer-last-sorting-mode 'recency))
  1952. (defun ibuffer-update-format ()
  1953. (when (null ibuffer-current-format)
  1954. (setq ibuffer-current-format 0))
  1955. (when (null ibuffer-formats)
  1956. (error "Ibuffer error: no formats!")))
  1957. (defun ibuffer-switch-format ()
  1958. "Switch the current display format."
  1959. (interactive)
  1960. (ibuffer-assert-ibuffer-mode)
  1961. (unless (consp ibuffer-formats)
  1962. (error "Ibuffer error: No formats!"))
  1963. (setq ibuffer-current-format
  1964. (if (>= ibuffer-current-format (1- (length (ibuffer-current-formats nil))))
  1965. 0
  1966. (1+ ibuffer-current-format)))
  1967. (ibuffer-update-format)
  1968. (ibuffer-redisplay t))
  1969. (defun ibuffer-update-title-and-summary (format)
  1970. (ibuffer-assert-ibuffer-mode)
  1971. ;; Don't do funky font-lock stuff here
  1972. (let ((inhibit-modification-hooks t))
  1973. (if (get-text-property (point-min) 'ibuffer-title)
  1974. (delete-region (point-min)
  1975. (next-single-property-change
  1976. (point-min) 'ibuffer-title)))
  1977. (goto-char (point-min))
  1978. (add-text-properties
  1979. (point)
  1980. (progn
  1981. (let ((opos (point)))
  1982. ;; Insert the title names.
  1983. (dolist (element format)
  1984. (insert
  1985. (if (stringp element)
  1986. element
  1987. (pcase-let ((`(,sym ,min ,_max ,align) element))
  1988. ;; Ignore a negative min when we're inserting the title
  1989. (when (cl-minusp min)
  1990. (setq min (- min)))
  1991. (let* ((name (or (get sym 'ibuffer-column-name)
  1992. (error "Unknown column %s in ibuffer-formats" sym)))
  1993. (len (length name))
  1994. (hmap (get sym 'header-mouse-map))
  1995. (strname (if (< len min)
  1996. (ibuffer-format-column name
  1997. (- min len)
  1998. align)
  1999. name)))
  2000. (when hmap
  2001. (setq
  2002. strname
  2003. (propertize strname 'mouse-face 'highlight 'keymap hmap)))
  2004. strname)))))
  2005. (add-text-properties opos (point) `(ibuffer-title-header t))
  2006. (insert "\n")
  2007. ;; Add the underlines
  2008. (let ((str (save-excursion
  2009. (forward-line -1)
  2010. (beginning-of-line)
  2011. (buffer-substring (point) (line-end-position)))))
  2012. (apply #'insert (mapcar
  2013. (lambda (c)
  2014. (if (not (or (eq c ?\s)
  2015. (eq c ?\n)))
  2016. ?-
  2017. ?\s))
  2018. str)))
  2019. (insert "\n"))
  2020. (point))
  2021. `(ibuffer-title t font-lock-face ,ibuffer-title-face))
  2022. ;; Now, insert the summary columns.
  2023. (goto-char (point-max))
  2024. (if (get-text-property (1- (point-max)) 'ibuffer-summary)
  2025. (delete-region (previous-single-property-change
  2026. (point-max) 'ibuffer-summary)
  2027. (point-max)))
  2028. (if ibuffer-display-summary
  2029. (add-text-properties
  2030. (point)
  2031. (progn
  2032. (insert "\n")
  2033. (dolist (element format)
  2034. (insert
  2035. (if (stringp element)
  2036. (make-string (length element) ?\s)
  2037. (pcase-let ((`(,sym ,min ,_max ,align) element))
  2038. ;; Ignore a negative min when we're inserting the title.
  2039. (when (cl-minusp min)
  2040. (setq min (- min)))
  2041. (let* ((summary
  2042. (if (get sym 'ibuffer-column-summarizer)
  2043. (funcall (get sym 'ibuffer-column-summarizer)
  2044. (get sym 'ibuffer-column-summary))
  2045. (make-string
  2046. (length (get sym 'ibuffer-column-name))
  2047. ?\s)))
  2048. (len (length summary)))
  2049. (if (< len min)
  2050. (ibuffer-format-column summary
  2051. (- min len)
  2052. align)
  2053. summary))))))
  2054. (point))
  2055. `(ibuffer-summary t)))))
  2056. (defun ibuffer-redisplay (&optional silent)
  2057. "Redisplay the current list of buffers.
  2058. This does not show new buffers; use `ibuffer-update' for that.
  2059. If optional arg SILENT is non-nil, do not display progress messages."
  2060. (interactive)
  2061. (ibuffer-forward-line 0)
  2062. (unless silent
  2063. (message "Redisplaying current buffer list..."))
  2064. (let ((blist (ibuffer-current-state-list)))
  2065. (when (and (null blist)
  2066. (featurep 'ibuf-ext)
  2067. (or ibuffer-filtering-qualifiers ibuffer-hidden-filter-groups))
  2068. (message "No buffers! (note: filtering in effect)"))
  2069. (ibuffer-redisplay-engine blist t)
  2070. (unless silent
  2071. (message "Redisplaying current buffer list...done"))
  2072. (ibuffer-forward-line 0)))
  2073. (defun ibuffer-update (arg &optional silent)
  2074. "Regenerate the list of all buffers.
  2075. Prefix arg non-nil means to toggle whether buffers that match
  2076. `ibuffer-maybe-show-predicates' should be displayed.
  2077. If optional arg SILENT is non-nil, do not display progress messages."
  2078. (interactive "P")
  2079. (if arg
  2080. (setq ibuffer-display-maybe-show-predicates
  2081. (not ibuffer-display-maybe-show-predicates)))
  2082. (ibuffer-forward-line 0)
  2083. (let* ((bufs (buffer-list))
  2084. (blist (ibuffer-filter-buffers
  2085. (current-buffer)
  2086. (if (and
  2087. (cadr bufs)
  2088. (eq ibuffer-always-show-last-buffer
  2089. :nomini)
  2090. (minibufferp (cadr bufs)))
  2091. (nth 2 bufs)
  2092. (cadr bufs))
  2093. (ibuffer-current-buffers-with-marks bufs)
  2094. ibuffer-display-maybe-show-predicates)))
  2095. (and (null blist)
  2096. (featurep 'ibuf-ext)
  2097. ibuffer-filtering-qualifiers
  2098. (message "No buffers! (note: filtering in effect)"))
  2099. (unless silent
  2100. (message "Updating buffer list..."))
  2101. (ibuffer-redisplay-engine blist arg)
  2102. (unless silent
  2103. (message "Updating buffer list...done")))
  2104. (if (eq ibuffer-shrink-to-minimum-size 'onewindow)
  2105. (ibuffer-shrink-to-fit t)
  2106. (when ibuffer-shrink-to-minimum-size
  2107. (ibuffer-shrink-to-fit)))
  2108. (ibuffer-forward-line 0)
  2109. ;; I tried to update this automatically from the mode-line-process format,
  2110. ;; but changing nil-ness of header-line-format while computing
  2111. ;; mode-line-format is asking a bit too much it seems. --Stef
  2112. (setq header-line-format
  2113. (and ibuffer-use-header-line
  2114. ibuffer-filtering-qualifiers
  2115. ibuffer-header-line-format)))
  2116. (defun ibuffer-sort-bufferlist (bmarklist)
  2117. (unless ibuffer-sorting-functions-alist
  2118. ;; make sure the sorting functions are loaded
  2119. (require 'ibuf-ext))
  2120. (let* ((sortdat (assq ibuffer-sorting-mode
  2121. ibuffer-sorting-functions-alist))
  2122. (func (nth 2 sortdat)))
  2123. (let ((result
  2124. ;; actually sort the buffers
  2125. (if (and sortdat func)
  2126. (sort bmarklist func)
  2127. bmarklist)))
  2128. ;; perhaps reverse the sorted buffer list
  2129. (if ibuffer-sorting-reversep
  2130. (nreverse result)
  2131. result))))
  2132. (defun ibuffer-insert-filter-group (name display-name filter-string format bmarklist)
  2133. (add-text-properties
  2134. (point)
  2135. (progn
  2136. (insert "[ " display-name " ]")
  2137. (point))
  2138. `(ibuffer-filter-group-name
  2139. ,name
  2140. font-lock-face ,ibuffer-filter-group-name-face
  2141. keymap ,ibuffer-mode-filter-group-map
  2142. mouse-face highlight
  2143. help-echo ,(let ((echo '(if tooltip-mode
  2144. "mouse-1: toggle marks in this group\nmouse-2: hide/show this filtering group"
  2145. "mouse-1: toggle marks mouse-2: hide/show")))
  2146. (if (> (length filter-string) 0)
  2147. `(concat ,filter-string
  2148. (if tooltip-mode "\n" " ")
  2149. ,echo)
  2150. echo))))
  2151. (insert "\n")
  2152. (when bmarklist
  2153. (put-text-property
  2154. (point)
  2155. (progn
  2156. (dolist (entry bmarklist)
  2157. (ibuffer-insert-buffer-line (car entry) (cdr entry) format))
  2158. (point))
  2159. 'ibuffer-filter-group
  2160. name)))
  2161. (defun ibuffer-redisplay-engine (bmarklist &optional _ignore)
  2162. (ibuffer-assert-ibuffer-mode)
  2163. (let* ((--ibuffer-insert-buffers-and-marks-format
  2164. (ibuffer-current-format))
  2165. (--ibuffer-expanded-format (mapcar #'ibuffer-expand-format-entry
  2166. (ibuffer-current-format t)))
  2167. (orig (count-lines (point-min) (point)))
  2168. ;; Inhibit font-lock caching tricks, since we're modifying the
  2169. ;; entire buffer at once
  2170. (inhibit-modification-hooks t)
  2171. (ext-loaded (featurep 'ibuf-ext))
  2172. (bgroups (if ext-loaded
  2173. (ibuffer-generate-filter-groups bmarklist)
  2174. (list (cons "Default" bmarklist)))))
  2175. (ibuffer-clear-summary-columns --ibuffer-expanded-format)
  2176. (unwind-protect
  2177. (progn
  2178. (setq buffer-read-only nil)
  2179. (erase-buffer)
  2180. (ibuffer-update-format)
  2181. (dolist (group (nreverse bgroups))
  2182. (let* ((name (car group))
  2183. (disabled (and ext-loaded
  2184. (member name ibuffer-hidden-filter-groups)))
  2185. (bmarklist (cdr group)))
  2186. (unless (and (null bmarklist)
  2187. (not disabled)
  2188. ext-loaded
  2189. (null ibuffer-show-empty-filter-groups))
  2190. (ibuffer-insert-filter-group
  2191. name
  2192. (if disabled (concat name " ...") name)
  2193. (if ext-loaded
  2194. (ibuffer-format-filter-group-data name)
  2195. "")
  2196. --ibuffer-insert-buffers-and-marks-format
  2197. (if disabled
  2198. nil
  2199. (ibuffer-sort-bufferlist bmarklist))))))
  2200. (ibuffer-update-title-and-summary --ibuffer-expanded-format))
  2201. (setq buffer-read-only t)
  2202. (set-buffer-modified-p ibuffer-did-modification)
  2203. (setq ibuffer-did-modification nil)
  2204. (goto-char (point-min))
  2205. (forward-line orig))))
  2206. ;;;###autoload
  2207. (defun ibuffer-list-buffers (&optional files-only)
  2208. "Display a list of buffers, in another window.
  2209. If optional argument FILES-ONLY is non-nil, then add a filter for
  2210. buffers which are visiting a file."
  2211. (interactive "P")
  2212. (ibuffer t nil (when files-only
  2213. '((filename . ".*"))) t))
  2214. ;;;###autoload
  2215. (defun ibuffer-other-window (&optional files-only)
  2216. "Like `ibuffer', but displayed in another window by default.
  2217. If optional argument FILES-ONLY is non-nil, then add a filter for
  2218. buffers which are visiting a file."
  2219. (interactive "P")
  2220. (ibuffer t nil (when files-only
  2221. '((filename . ".*")))))
  2222. ;;;###autoload
  2223. (defun ibuffer (&optional other-window-p name qualifiers noselect
  2224. shrink filter-groups formats)
  2225. "Begin using Ibuffer to edit a list of buffers.
  2226. Type `h' after entering ibuffer for more information.
  2227. All arguments are optional.
  2228. OTHER-WINDOW-P says to use another window.
  2229. NAME specifies the name of the buffer (defaults to \"*Ibuffer*\").
  2230. QUALIFIERS is an initial set of filtering qualifiers to use;
  2231. see `ibuffer-filtering-qualifiers'.
  2232. NOSELECT means don't select the Ibuffer buffer.
  2233. SHRINK means shrink the buffer to minimal size. The special
  2234. value `onewindow' means always use another window.
  2235. FILTER-GROUPS is an initial set of filtering groups to use;
  2236. see `ibuffer-filter-groups'.
  2237. FORMATS is the value to use for `ibuffer-formats'.
  2238. If specified, then the variable `ibuffer-formats' will have
  2239. that value locally in this buffer."
  2240. (interactive "P")
  2241. (when ibuffer-use-other-window
  2242. (setq other-window-p t))
  2243. (let ((buf (get-buffer-create (or name "*Ibuffer*"))))
  2244. (if other-window-p
  2245. (or (and noselect (display-buffer buf t))
  2246. (pop-to-buffer buf t))
  2247. (funcall (if noselect #'display-buffer #'switch-to-buffer) buf))
  2248. (with-current-buffer buf
  2249. (save-selected-window
  2250. ;; We switch to the buffer's window in order to be able
  2251. ;; to modify the value of point
  2252. (select-window (get-buffer-window buf 0))
  2253. (or (derived-mode-p 'ibuffer-mode)
  2254. (ibuffer-mode))
  2255. (when shrink
  2256. (setq ibuffer-shrink-to-minimum-size shrink))
  2257. (when qualifiers
  2258. (require 'ibuf-ext)
  2259. (setq ibuffer-filtering-qualifiers qualifiers))
  2260. (when filter-groups
  2261. (require 'ibuf-ext)
  2262. (setq ibuffer-filter-groups filter-groups))
  2263. (when formats
  2264. (set (make-local-variable 'ibuffer-formats) formats))
  2265. (ibuffer-update nil)
  2266. ;; Skip the group name by default.
  2267. (ibuffer-forward-line 0 t)
  2268. (unwind-protect
  2269. (progn
  2270. (setq buffer-read-only nil)
  2271. (run-hooks 'ibuffer-hook))
  2272. (setq buffer-read-only t))
  2273. (unless ibuffer-expert
  2274. (message "Commands: m, u, t, RET, g, k, S, D, Q; q to quit; h for help"))))))
  2275. ;;;###autoload
  2276. (defun ibuffer-jump (&optional other-window)
  2277. "Call Ibuffer and set point at the line listing the current buffer.
  2278. If optional arg OTHER-WINDOW is non-nil, then use another window."
  2279. (interactive "P")
  2280. (let ((name (buffer-name)))
  2281. (ibuffer other-window)
  2282. (ignore-errors (ibuffer-jump-to-buffer name))))
  2283. (put 'ibuffer-mode 'mode-class 'special)
  2284. (define-derived-mode ibuffer-mode special-mode "IBuffer"
  2285. "A major mode for viewing a list of buffers.
  2286. In Ibuffer, you can conveniently perform many operations on the
  2287. currently open buffers, in addition to filtering your view to a
  2288. particular subset of them, and sorting by various criteria.
  2289. Operations on marked buffers:
  2290. \\<ibuffer-mode-map>
  2291. `\\[ibuffer-do-save]' - Save the marked buffers
  2292. `\\[ibuffer-do-view]' - View the marked buffers in this frame.
  2293. `\\[ibuffer-do-view-other-frame]' - View the marked buffers in another frame.
  2294. `\\[ibuffer-do-revert]' - Revert the marked buffers.
  2295. `\\[ibuffer-do-toggle-read-only]' - Toggle read-only state of marked buffers.
  2296. `\\[ibuffer-do-delete]' - Kill the marked buffers.
  2297. `\\[ibuffer-do-isearch]' - Do incremental search in the marked buffers.
  2298. `\\[ibuffer-do-isearch-regexp]' - Isearch for regexp in the marked buffers.
  2299. `\\[ibuffer-do-replace-regexp]' - Replace by regexp in each of the marked
  2300. buffers.
  2301. `\\[ibuffer-do-query-replace]' - Query replace in each of the marked buffers.
  2302. `\\[ibuffer-do-query-replace-regexp]' - As above, with a regular expression.
  2303. `\\[ibuffer-do-print]' - Print the marked buffers.
  2304. `\\[ibuffer-do-occur]' - List lines in all marked buffers which match
  2305. a given regexp (like the function `occur').
  2306. `\\[ibuffer-do-shell-command-pipe]' - Pipe the contents of the marked
  2307. buffers to a shell command.
  2308. `\\[ibuffer-do-shell-command-pipe-replace]' - Replace the contents of the marked
  2309. buffers with the output of a shell command.
  2310. `\\[ibuffer-do-shell-command-file]' - Run a shell command with the
  2311. buffer's file as an argument.
  2312. `\\[ibuffer-do-eval]' - Evaluate a form in each of the marked buffers. This
  2313. is a very flexible command. For example, if you want to make all
  2314. of the marked buffers read only, try using (read-only-mode 1) as
  2315. the input form.
  2316. `\\[ibuffer-do-view-and-eval]' - As above, but view each buffer while the form
  2317. is evaluated.
  2318. `\\[ibuffer-do-kill-lines]' - Remove the marked lines from the *Ibuffer* buffer,
  2319. but don't kill the associated buffer.
  2320. `\\[ibuffer-do-kill-on-deletion-marks]' - Kill all buffers marked for deletion.
  2321. Marking commands:
  2322. `\\[ibuffer-mark-forward]' - Mark the buffer at point.
  2323. `\\[ibuffer-toggle-marks]' - Unmark all currently marked buffers, and mark
  2324. all unmarked buffers.
  2325. `\\[ibuffer-change-marks]' - Change the mark used on marked buffers.
  2326. `\\[ibuffer-unmark-forward]' - Unmark the buffer at point.
  2327. `\\[ibuffer-unmark-backward]' - Unmark the buffer at point, and move to the
  2328. previous line.
  2329. `\\[ibuffer-unmark-all]' - Unmark buffers marked with MARK.
  2330. `\\[ibuffer-unmark-all-marks]' - Unmark all marked buffers.
  2331. `\\[ibuffer-mark-by-mode]' - Mark buffers by major mode.
  2332. `\\[ibuffer-mark-unsaved-buffers]' - Mark all \"unsaved\" buffers.
  2333. This means that the buffer is modified, and has an associated file.
  2334. `\\[ibuffer-mark-modified-buffers]' - Mark all modified buffers,
  2335. regardless of whether or not they have an associated file.
  2336. `\\[ibuffer-mark-special-buffers]' - Mark all buffers whose name begins and
  2337. ends with `*'.
  2338. `\\[ibuffer-mark-dissociated-buffers]' - Mark all buffers which have
  2339. an associated file, but that file doesn't currently exist.
  2340. `\\[ibuffer-mark-read-only-buffers]' - Mark all read-only buffers.
  2341. `\\[ibuffer-mark-dired-buffers]' - Mark buffers in `dired' mode.
  2342. `\\[ibuffer-mark-help-buffers]' - Mark buffers in `help-mode', `apropos-mode', etc.
  2343. `\\[ibuffer-mark-old-buffers]' - Mark buffers older than `ibuffer-old-time'.
  2344. `\\[ibuffer-mark-for-delete]' - Mark the buffer at point for deletion.
  2345. `\\[ibuffer-mark-by-name-regexp]' - Mark buffers by their name, using a regexp.
  2346. `\\[ibuffer-mark-by-mode-regexp]' - Mark buffers by their major mode, using a regexp.
  2347. `\\[ibuffer-mark-by-file-name-regexp]' - Mark buffers by their filename, using a regexp.
  2348. `\\[ibuffer-mark-by-content-regexp]' - Mark buffers by their content, using a regexp.
  2349. `\\[ibuffer-mark-by-locked]' - Mark all locked buffers.
  2350. Filtering commands:
  2351. `\\[ibuffer-filter-chosen-by-completion]' - Select and apply filter chosen by completion.
  2352. `\\[ibuffer-filter-by-mode]' - Add a filter by any major mode.
  2353. `\\[ibuffer-filter-by-used-mode]' - Add a filter by a major mode now in use.
  2354. `\\[ibuffer-filter-by-derived-mode]' - Add a filter by derived mode.
  2355. `\\[ibuffer-filter-by-name]' - Add a filter by buffer name.
  2356. `\\[ibuffer-filter-by-content]' - Add a filter by buffer content.
  2357. `\\[ibuffer-filter-by-basename]' - Add a filter by basename.
  2358. `\\[ibuffer-filter-by-directory]' - Add a filter by directory name.
  2359. `\\[ibuffer-filter-by-filename]' - Add a filter by filename.
  2360. `\\[ibuffer-filter-by-file-extension]' - Add a filter by file extension.
  2361. `\\[ibuffer-filter-by-modified]' - Add a filter by modified buffers.
  2362. `\\[ibuffer-filter-by-predicate]' - Add a filter by an arbitrary Lisp predicate.
  2363. `\\[ibuffer-filter-by-size-gt]' - Add a filter by buffer size.
  2364. `\\[ibuffer-filter-by-size-lt]' - Add a filter by buffer size.
  2365. `\\[ibuffer-filter-by-starred-name]' - Add a filter by special buffers.
  2366. `\\[ibuffer-filter-by-visiting-file]' - Add a filter by buffers visiting files.
  2367. `\\[ibuffer-save-filters]' - Save the current filters with a name.
  2368. `\\[ibuffer-switch-to-saved-filters]' - Switch to previously saved filters.
  2369. `\\[ibuffer-add-saved-filters]' - Add saved filters to current filters.
  2370. `\\[ibuffer-and-filter]' - Replace the top two filters with their logical AND.
  2371. `\\[ibuffer-or-filter]' - Replace the top two filters with their logical OR.
  2372. `\\[ibuffer-pop-filter]' - Remove the top filter.
  2373. `\\[ibuffer-negate-filter]' - Invert the logical sense of the top filter.
  2374. `\\[ibuffer-decompose-filter]' - Break down the topmost filter.
  2375. `\\[ibuffer-filter-disable]' - Remove all filtering currently in effect.
  2376. Filter group commands:
  2377. `\\[ibuffer-filters-to-filter-group]' - Create filter group from filters.
  2378. `\\[ibuffer-pop-filter-group]' - Remove top filter group.
  2379. `\\[ibuffer-forward-filter-group]' - Move to the next filter group.
  2380. `\\[ibuffer-backward-filter-group]' - Move to the previous filter group.
  2381. `\\[ibuffer-clear-filter-groups]' - Remove all active filter groups.
  2382. `\\[ibuffer-save-filter-groups]' - Save the current groups with a name.
  2383. `\\[ibuffer-switch-to-saved-filter-groups]' - Restore previously saved groups.
  2384. `\\[ibuffer-delete-saved-filter-groups]' - Delete previously saved groups.
  2385. Sorting commands:
  2386. `\\[ibuffer-toggle-sorting-mode]' - Rotate between the various sorting modes.
  2387. `\\[ibuffer-invert-sorting]' - Reverse the current sorting order.
  2388. `\\[ibuffer-do-sort-by-alphabetic]' - Sort the buffers lexicographically.
  2389. `\\[ibuffer-do-sort-by-filename/process]' - Sort the buffers by the file name.
  2390. `\\[ibuffer-do-sort-by-recency]' - Sort the buffers by last viewing time.
  2391. `\\[ibuffer-do-sort-by-size]' - Sort the buffers by size.
  2392. `\\[ibuffer-do-sort-by-major-mode]' - Sort the buffers by major mode.
  2393. Other commands:
  2394. `\\[ibuffer-update]' - Regenerate the list of all buffers.
  2395. Prefix arg means to toggle whether buffers that match
  2396. `ibuffer-maybe-show-predicates' should be displayed.
  2397. `\\[ibuffer-switch-format]' - Change the current display format.
  2398. `\\[forward-line]' - Move point to the next line.
  2399. `\\[previous-line]' - Move point to the previous line.
  2400. `\\[describe-mode]' - This help.
  2401. `\\[ibuffer-diff-with-file]' - View the differences between this buffer
  2402. and its associated file.
  2403. `\\[ibuffer-visit-buffer]' - View the buffer on this line.
  2404. `\\[ibuffer-visit-buffer-other-window]' - As above, but in another window.
  2405. `\\[ibuffer-visit-buffer-other-window-noselect]' - As both above, but don't select
  2406. the new window.
  2407. `\\[ibuffer-bury-buffer]' - Bury (not kill!) the buffer on this line.
  2408. ** Information on Filtering:
  2409. You can filter your ibuffer view via different criteria. Each Ibuffer
  2410. buffer has its own stack of active filters. For example, suppose you
  2411. are working on an Emacs Lisp project. You can create an Ibuffer
  2412. buffer displays buffers in just `emacs-lisp' modes via
  2413. `\\[ibuffer-filter-by-mode] emacs-lisp-mode RET'. In this case, there
  2414. is just one entry on the filtering stack.
  2415. You can also combine filters. The various filtering commands push a
  2416. new filter onto the stack, and the filters combine to show just
  2417. buffers which satisfy ALL criteria on the stack. For example, suppose
  2418. you only want to see buffers in `emacs-lisp' mode, whose names begin
  2419. with \"gnus\". You can accomplish this via:
  2420. \\[ibuffer-filter-by-mode] emacs-lisp-mode RET
  2421. \\[ibuffer-filter-by-name] ^gnus RET
  2422. Additionally, you can OR the top two filters together with
  2423. `\\[ibuffer-or-filters]'. To see all buffers in either
  2424. `emacs-lisp-mode' or `lisp-interaction-mode', type:
  2425. \\[ibuffer-filter-by-mode] emacs-lisp-mode RET
  2426. \\[ibuffer-filter-by-mode] lisp-interaction-mode RET
  2427. \\[ibuffer-or-filters]
  2428. Filters can also be saved and restored using mnemonic names: see the
  2429. functions `ibuffer-save-filters' and `ibuffer-switch-to-saved-filters'.
  2430. To remove the top filter on the stack, use `\\[ibuffer-pop-filter]', and
  2431. to disable all filtering currently in effect, use
  2432. `\\[ibuffer-filter-disable]'.
  2433. ** Filter Groups:
  2434. Once one has mastered filters, the next logical step up is \"filter
  2435. groups\". A filter group is basically a named group of buffers which
  2436. match a filter, which are displayed together in an Ibuffer buffer. To
  2437. create a filter group, simply use the regular functions to create a
  2438. filter, and then type `\\[ibuffer-filters-to-filter-group]'.
  2439. A quick example will make things clearer. Suppose that one wants to
  2440. group all of one's Emacs Lisp buffers together. To do this, type:
  2441. \\[ibuffer-filter-by-mode] emacs-lisp-mode RET
  2442. \\[ibuffer-filters-to-filter-group] emacs lisp buffers RET
  2443. You may, of course, name the group whatever you want; it doesn't have
  2444. to be \"emacs lisp buffers\". Filter groups may be composed of any
  2445. arbitrary combination of filters.
  2446. Just like filters themselves, filter groups act as a stack. Buffers
  2447. will not be displayed multiple times if they would be included in
  2448. multiple filter groups; instead, the first filter group is used. The
  2449. filter groups are displayed in this order of precedence.
  2450. You may rearrange filter groups by using the regular
  2451. `\\[ibuffer-kill-line]' and `\\[ibuffer-yank]' pair. Yanked groups
  2452. will be inserted before the group at point."
  2453. ;; Include state info next to the mode name.
  2454. (set (make-local-variable 'mode-line-process)
  2455. '(" by "
  2456. (ibuffer-sorting-mode (:eval (symbol-name ibuffer-sorting-mode))
  2457. "view time")
  2458. (ibuffer-sorting-reversep " [rev]")
  2459. (ibuffer-auto-mode " (Auto)")
  2460. ;; Only list the filters if they're not already in the header-line.
  2461. (header-line-format
  2462. ""
  2463. (:eval (if (functionp 'ibuffer-format-qualifier)
  2464. (mapconcat 'ibuffer-format-qualifier
  2465. ibuffer-filtering-qualifiers ""))))))
  2466. ;; `ibuffer-update' puts this on header-line-format when needed.
  2467. (setq ibuffer-header-line-format
  2468. ;; Display the part that won't be in the mode-line.
  2469. `("" ,mode-name
  2470. ,@(mapcar (lambda (elem)
  2471. (if (eq (car-safe elem) 'header-line-format)
  2472. (nth 2 elem) elem))
  2473. mode-line-process)))
  2474. (setq buffer-read-only t)
  2475. (buffer-disable-undo)
  2476. (setq truncate-lines ibuffer-truncate-lines)
  2477. ;; This makes things less ugly for Emacs 21 users with a non-nil
  2478. ;; `show-trailing-whitespace'.
  2479. (setq show-trailing-whitespace nil)
  2480. ;; disable `show-paren-mode' buffer-locally
  2481. (if (bound-and-true-p show-paren-mode)
  2482. (set (make-local-variable 'show-paren-mode) nil))
  2483. (set (make-local-variable 'revert-buffer-function)
  2484. #'ibuffer-update)
  2485. (set (make-local-variable 'ibuffer-sorting-mode)
  2486. ibuffer-default-sorting-mode)
  2487. (set (make-local-variable 'ibuffer-sorting-reversep)
  2488. ibuffer-default-sorting-reversep)
  2489. (set (make-local-variable 'ibuffer-shrink-to-minimum-size)
  2490. ibuffer-default-shrink-to-minimum-size)
  2491. (set (make-local-variable 'ibuffer-display-maybe-show-predicates)
  2492. ibuffer-default-display-maybe-show-predicates)
  2493. (set (make-local-variable 'ibuffer-filtering-qualifiers) nil)
  2494. (set (make-local-variable 'ibuffer-filter-groups) nil)
  2495. (set (make-local-variable 'ibuffer-filter-group-kill-ring) nil)
  2496. (set (make-local-variable 'ibuffer-hidden-filter-groups) nil)
  2497. (set (make-local-variable 'ibuffer-compiled-formats) nil)
  2498. (set (make-local-variable 'ibuffer-cached-formats) nil)
  2499. (set (make-local-variable 'ibuffer-cached-eliding-string) nil)
  2500. (set (make-local-variable 'ibuffer-cached-elide-long-columns) nil)
  2501. (set (make-local-variable 'ibuffer-current-format) nil)
  2502. (set (make-local-variable 'ibuffer-did-modification) nil)
  2503. (set (make-local-variable 'ibuffer-tmp-hide-regexps) nil)
  2504. (set (make-local-variable 'ibuffer-tmp-show-regexps) nil)
  2505. (define-key ibuffer-mode-map [menu-bar edit] 'undefined)
  2506. (define-key ibuffer-mode-map [menu-bar operate] (cons "Operate" ibuffer-mode-operate-map))
  2507. (ibuffer-update-format)
  2508. (when ibuffer-default-directory
  2509. (setq default-directory ibuffer-default-directory))
  2510. (add-hook 'change-major-mode-hook 'font-lock-defontify nil t))
  2511. (provide 'ibuffer)
  2512. (run-hooks 'ibuffer-load-hook)
  2513. ;;; ibuffer.el ends here