├── .gitignore
├── .travis.yml
├── Cask
├── LICENSE
├── README.org
├── screen.png
├── spaceline-config.el
├── spaceline-segments.el
├── spaceline.el
└── tests.el
/.gitignore:
--------------------------------------------------------------------------------
1 | *.elc
2 | /.cask
3 | *-autoloads.el
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: generic
2 | dist: trusty
3 | sudo: false
4 |
5 | branches:
6 | only:
7 | - master
8 | - codegen
9 | env:
10 | - EVM_EMACS=emacs-24.4-travis
11 | - EVM_EMACS=emacs-24.5-travis
12 | - EVM_EMACS=emacs-25.1-travis
13 | - EVM_EMACS=emacs-25.2-travis
14 | - EVM_EMACS=emacs-25.3-travis
15 | - EVM_EMACS=emacs-26.1-travis
16 | - EVM_EMACS=emacs-git-snapshot-travis
17 |
18 | matrix:
19 | allow_failtures:
20 | env:
21 | - EVM_EMACS=emacs-git-snapshot-travis
22 |
23 | before_install:
24 | - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh
25 | - evm install $EVM_EMACS --use --skip
26 |
27 | install:
28 | - cask install
29 |
30 | script:
31 | - cask emacs --batch -l ert -l spaceline.el -l tests.el -f ert-run-tests-batch-and-exit
32 |
--------------------------------------------------------------------------------
/Cask:
--------------------------------------------------------------------------------
1 | (source gnu)
2 | (source melpa)
3 |
4 | (package-file "spaceline.el")
5 |
6 | (development
7 | (depends-on "f")
8 | (depends-on "ecukes")
9 | (depends-on "ert-runner")
10 | (depends-on "el-mock"))
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
676 |
--------------------------------------------------------------------------------
/README.org:
--------------------------------------------------------------------------------
1 | #+TITLE: Spaceline
2 |
3 | [[https://melpa.org/#/spaceline][http://melpa.org/packages/spaceline-badge.svg]] [[https://stable.melpa.org/#/spaceline][https://stable.melpa.org/packages/spaceline-badge.svg]] [[https://travis-ci.org/TheBB/spaceline][https://travis-ci.org/TheBB/spaceline.svg]] [[https://github.com/syl20bnr/spacemacs][file:https://cdn.rawgit.com/syl20bnr/spacemacs/442d025779da2f62fc86c2082703697714db6514/assets/spacemacs-badge.svg]]
4 |
5 | * Contents :TOC_2_gh:
6 | - [[#introduction][Introduction]]
7 | - [[#the-default-themes][The default themes]]
8 | - [[#optional-dependencies][Optional dependencies]]
9 | - [[#troubleshooting][Troubleshooting]]
10 | - [[#moderate-configuration][Moderate configuration]]
11 | - [[#turning-segments-on-and-off][Turning segments on and off]]
12 | - [[#the-highlight-face][The highlight face]]
13 | - [[#other-faces][Other faces]]
14 | - [[#powerline-separators][Powerline separators]]
15 | - [[#hooks][Hooks]]
16 | - [[#unicode-numbers][Unicode numbers]]
17 | - [[#minor-modes-separator][Minor modes separator]]
18 | - [[#org-clock][Org clock]]
19 | - [[#deep-configuration][Deep configuration]]
20 | - [[#segments][Segments]]
21 | - [[#defining-a-segment][Defining a segment]]
22 | - [[#properties][Properties]]
23 | - [[#bindings][Bindings]]
24 | - [[#compiling-a-mode-line][Compiling a mode-line]]
25 | - [[#tweaking-or-defining-your-own-mode-line][Tweaking or defining your own mode-line]]
26 |
27 | * Introduction
28 | This is the package that provides [[http://spacemacs.org/][Spacemacs]] with its famous mode-line theme. It
29 | has been extracted as an independent package for general fun and profit.
30 |
31 | This package provides features for three kinds of users.
32 |
33 | 1. You just want to use the Spacemacs mode-line theme and forget about it.
34 | 2. You want to use something similar to the Spacemacs mode-line theme, but with
35 | a handful of easy tweaks.
36 | 3. You want an easy-to-use library for building your own mode-line from scratch,
37 | and you think the Spacemacs theme looks good.
38 |
39 | The functionality for each are described in the following sections.
40 |
41 | The files in this package are organized as follows. Choose which you want to
42 | load based on what you want to do.
43 |
44 | - =spaceline.el=: Contains the core library used to define segments and render
45 | the modeline. It defines no segments by itself except the =global= segment.
46 | (See below.)
47 | - =spaceline-segments.el=: Defines all the segments used by the default
48 | Spacemacs theme, but doesn’t do anything with them.
49 | - =spaceline-config.el=: Defines the default themes.
50 |
51 | * The default themes
52 | To install it, just load =spaceline-config= and call the theme function you
53 | want. E.g.
54 |
55 | #+BEGIN_SRC emacs-lisp
56 | (require 'spaceline-config)
57 | (spaceline-spacemacs-theme)
58 | #+END_SRC
59 |
60 | The package comes bundled with two themes:
61 |
62 | - =spaceline-spacemacs-theme=: The theme used by Spacemacs
63 | - =spaceline-emacs-theme=: A theme which is similar to the one used by
64 | Spacemacs, but which has been designed to look good without the dependencies
65 | that the Spacemacs theme needs.
66 |
67 | In addition, Spaceline supports custom themes for Info+ and Helm. These can be
68 | enabled through global minor modes:
69 |
70 | - =spaceline-helm-mode=
71 | - =spaceline-info-mode= (requires the [[http://www.emacswiki.org/emacs/InfoPlus][info+]] package)
72 |
73 | These are also defined in =spaceline-config.el=.
74 |
75 | ** Optional dependencies
76 | These themes include several segments that depend on third-party packages. If
77 | these packages are not installed, these segments will be invisible and not show
78 | any output. As such, they can be considered /optional/ dependencies.
79 |
80 | Here follows a brief list of these dependencies. For more information consult
81 | the upstream sources.
82 |
83 | *** Persp-mode
84 | [[https://github.com/Bad-ptr/persp-mode.el][Persp-mode]] is a powerful workspace-like package. Spaceline shows the current
85 | workspace name.
86 |
87 | *** Eyebrowse
88 | [[https://github.com/wasamasa/eyebrowse][Eyebrowse]] is a simpler workspace-like package. If it is installed, The Spacemacs
89 | theme will show the current workspace number. The Emacs theme uses the workspace
90 | number as a fallback for the perspective name: thus if persp-mode is installed,
91 | the Eyebrowse workspace will not be shown.
92 |
93 | *** Winum
94 | [[https://github.com/deb0ch/winum.el][Winum]] shows a number for each window, and it works with both themes.
95 |
96 | To prevent =winum= from inserting its own number in the mode-line, you have to
97 | set =winum-auto-setup-mode-line= to nil before activating =winum-mode=:
98 |
99 | #+BEGIN_SRC emacs-lisp
100 | (setq winum-auto-setup-mode-line nil)
101 | (winum-mode)
102 | #+END_SRC
103 |
104 | *** Auto-compile
105 | [[https://github.com/tarsius/auto-compile][Auto-compile]] automatically compiles Emacs Lisp files on save if there is an
106 | older byte-compiled file. Spaceline shows warnings when they occur.
107 |
108 | *** Anzu
109 | [[https://github.com/syohex/emacs-anzu][Anzu]] shows the current match and the total number of matches while searching.
110 |
111 | Note that Anzu inserts itself in the modeline, to let spaceline handle the
112 | modeline, make sure to =(setq anzu-cons-mode-line-p nil)= or customize it.
113 |
114 | *** Flycheck
115 | [[https://github.com/flycheck/flycheck/][Flycheck]] is a powerful syntax-checking package. Spaceline shows errors, warnings
116 | and notifications from it.
117 |
118 | *** ERC
119 | [[http://www.emacswiki.org/emacs/ERC][ERC]] is an IRC client built in to Emacs. Spaceline shows channels with new
120 | messages if you have =erc-track= turned on.
121 |
122 | *** Org
123 | Spaceline shows the currently clocking [[http://orgmode.org/][org-mode]] task.
124 |
125 | *** Org-pomodoro
126 | Spaceline integrates with [[HTtps://github.com/lolownia/org-pomodoro][org-pomodoro]] by showing its clocks.
127 |
128 | *** Python virtual environments
129 | The currently active environments as reported by [[https://github.com/proofit404/pyenv-mode][pyenv-mode]] or [[https://github.com/jorgenschaefer/pyvenv][pyvenv]] are shown
130 | in Spaceline.
131 |
132 | *** Nyan cat
133 | [[https://github.com/TeMPOraL/nyan-mode][Nyan-mode]] shows the current position in the buffer with kittens and rainbows.
134 |
135 | *** Fancy battery
136 | [[https://github.com/lunaryorn/fancy-battery.el][Fancy-battery]] shows battery information in the modeline.
137 |
138 | *** Evil
139 | [[https://bitbucket.org/lyro/evil/wiki/Home][Evil]] makes Emacs behave like Vim. The first segment in the Spacemacs theme shows
140 | the current Evil state if all the other dependencies do not report information
141 | (i.e. no perspective, workspace or window number). The Emacs theme does not
142 | include any information from Evil.
143 |
144 | You can color the modeline according to the current Evil state by setting
145 | =spaceline-highlight-face-func= to =spaceline-highlight-face-evil-state=.
146 |
147 | ** Troubleshooting
148 | There are a number of reasons why Spaceline might look different on your setup
149 | compared to Spacemacs proper. Some of the most important ones are addressed here.
150 |
151 | - You’re missing an optional dependency. Spacemacs includes packages that
152 | display information in the mode-line. The leftmost segment is invisible if
153 | =eyebrowse-mode=, =persp-mode=, =window-numbering-mode= and =evil= are all not
154 | present. If you don’t wish to use these packages, consider using the Emacs
155 | theme.
156 |
157 | - Consider setting or increasing the value of =powerline-height= to give your
158 | mode-line some room to breathe.
159 |
160 | - The default powerline separator is =arrow=, but Spacemacs uses =wave=. You
161 | should try out various settings of =powerline-default-separator= to find the
162 | one that works for you. Note that you need to recompile the modeline with =M-x
163 | spaceline-compile= after setting this variable.
164 |
165 | - If you’re using =eyebrowse-mode= or =window-numbering-mode=, consider setting
166 | =spaceline-workspace-numbers-unicode= and =spaceline-window-numbers-unicode=
167 | to =t= to get the nice-looking unicode numbers seen in the screenshot.
168 |
169 | - Use [[https://github.com/emacsmirror/diminish][Diminish]] to tweak the output of the minor modes segment.
170 |
171 | - To get the mode-line highlight to change color depending on the evil state,
172 | set =spaceline-highlight-face-func= to =spaceline-highlight-face-evil-state=.
173 |
174 | * Moderate configuration
175 |
176 | ** Turning segments on and off
177 | Each segment has a variable =spaceline-NAME-p= that can switch the segment off
178 | by setting it to =nil=. There are also three convenient interactive functions
179 | for toggling:
180 |
181 | - =spaceline-toggle-=
182 | - =spaceline-toggle--on=
183 | - =spaceline-toggle--off=
184 |
185 | These can be bound to whichever keys you like.
186 |
187 | Here is a complete list of segments bundled with Spacemacs.
188 |
189 | - =persp-name=: integrates with =persp-mode=.
190 | - =workspace-number=: integrates with =eyebrowse=.
191 | - =window-number=: integrates with =window-numbering=.
192 | - =evil-state=: shows the current evil state, integrates with =evil=.
193 | - =anzu=: integrates with =anzu=.
194 | - =auto-compile=: integrates with =auto-compile=.
195 | - =buffer-modified=: the standard marker denoting whether the buffer is modified
196 | or not.
197 | - =buffer-size=: the size of the buffer.
198 | - =buffer-id=: the name of the buffer.
199 | - =remote-host=: the host for remote buffers.
200 | - =major-mode=: the current major mode.
201 | - =flycheck-error=: number of flycheck errors, integrates with =flycheck=.
202 | - =flycheck-warning=: number of flycheck warnings, integrates with =flycheck=.
203 | - =flycheck-info=: number of flycheck notifications, integrates with =flycheck=.
204 | - =minor-modes=: the currently enabled minor modes. The output of this segment
205 | can be tweaked with [[https://github.com/emacsmirror/diminish][Diminish]].
206 | - =process=: the background process associated with the buffer, if any.
207 | - =erc-track=: IRC channels with new messages, integrates with =erc=.
208 | - =version-control=: version control information.
209 | - =org-pomodoro=: integrates with =org-pomodoro=.
210 | - =org-clock=: the current org clock, integrates with =org=.
211 | - =nyan-cat=: integrates with =nyan-mode=.
212 | - =battery=: integrates with =fancy-battery-mode=.
213 | - =which-function=: integrates with =which-function-mode=.
214 | - =python-pyvenv=: integrates with =pyvenv=.
215 | - =python-pyenv=: integrates with =pyenv=.
216 | - =paradox-menu=: integrates with =paradox=.
217 | - =selection-info=: information about the currently active selection, if any.
218 | - =input-method=: shows the current active input method, if any.
219 | - =buffer-encoding-abbrev=: the line ending convention used in the current
220 | buffer (unix, dos or mac).
221 | - =point-position=: the value of point (disabled by default).
222 | - =line-column=: current line and column.
223 | - =global=: meta-segment used by third-party packages.
224 | - =buffer-position=: shows the current position in the buffer as a percentage.
225 | - =hud=: shows the currently visible part of the buffer.
226 |
227 | In addition, the following segments are defined, but are not used in the default
228 | themes.
229 |
230 | - =line=: current line.
231 | - =column=: current column.
232 | - =projectile-root=: root of current projectile project, integrates with
233 | =projectile=.
234 | - =buffer-encoding=: like =buffer-encoding-abbrev=, but not abbreviated.
235 |
236 | For the custom helm modeline, the following segments are used.
237 |
238 | - =helm-buffer-id=: the name of the current helm session.
239 | - =helm-number=: number of helm candidates.
240 | - =helm-help=: a brief help string.
241 | - =helm-prefix-argument=: shows the prefix argument, if any.
242 | - =helm-follow=: shows whether =helm-follow= is turned on.
243 |
244 | For the custom info modeline, the following segments are used.
245 |
246 | - =info-topic=: the current topic.
247 | - =info-nodes=: breadcrumbs.
248 |
249 | ** The highlight face
250 | The highlight face is the face that (by default) is a sharp orange, used e.g. by
251 | the HUD segment on the far right, and the first segment on the left (note that
252 | it may be invisible if you are using the Spacemacs theme but not some of its
253 | optional dependencies). The actual face used as a highlight face is determined
254 | by a function, which can be configured by setting the value of
255 | =spaceline-highlight-face-func=. Spaceline comes with three choices, but of
256 | course you can write your own:
257 |
258 | - =spaceline-highlight-face-default=: Uses the orange, all the time. This is the
259 | default.
260 | - =spaceline-highlight-face-evil-state=: Chooses a face determined by the
261 | current evil state. The face corresponding to each state is determined by the
262 | association list =spaceline-evil-state-faces=, which contains default values
263 | for the standard evil states. (Spacemacs has a few more.)
264 | - =spaceline-highlight-face-modified=: Chooses a face determined by the status
265 | of the current buffer (modified, unmodified or read-only).
266 |
267 | Note that the highlight face is only used in the active window.
268 |
269 | ** Other faces
270 | In the active window, the mode-line will use these faces:
271 |
272 | - =powerline-active1=
273 | - =powerline-active2=
274 | - =mode-line=
275 |
276 | And in inactive windows:
277 |
278 | - =powerline-inactive1=
279 | - =powerline-inactive2=
280 | - =mode-line-inactive=
281 |
282 | To override this, you can set the variable =spaceline-face-func=. This should be
283 | a function that accepts two arguments and returns a face symbol. The arguments
284 | are:
285 |
286 | - =face=: either of =face1=, =face2=, =line= and =highlight=.
287 | - =active=: a boolean determining whether the window is active or not.
288 |
289 | If this function is not set, Spaceline delegates the highlight face to
290 | =spaceline-highlight-face-func= (see above), and picks the others according to
291 | the above scheme.
292 |
293 | ** Powerline separators
294 | Set =powerline-default-separator= to configure this. The docstring for that
295 | variable enumerates the choices.
296 |
297 | Each separator comes in two directions: left and right. The variables
298 | =spaceline-separator-dir-left= and =spaceline-separator-dir-right= specify which
299 | directions to alternate between on the left and right side, respectively.
300 |
301 | By default these variables are set to =nil=, which means Spaceline will choose
302 | the directions that look best for your chosen separator style. However, you can
303 | set to override this, for example:
304 |
305 | #+BEGIN_SRC emacs-lisp
306 | (setq spaceline-separator-dir-left '(left . left))
307 | (setq spaceline-separator-dir-right '(right . right))
308 | #+END_SRC
309 |
310 | Note that you must recompile the modelines after changing the separators, by
311 | calling =M-x spaceline-compile=.
312 |
313 | ** Hooks
314 | The hook =spaceline-pre-hook= is executed before rendering the modeline. Don’t
315 | put any performance-intensive functions here!
316 |
317 | ** Unicode numbers
318 | By default, Spacemacs displays window numbers and workspace numbers in nice
319 | unicode symbols. To do this in Spaceline, set =spaceline-window-numbers-unicode=
320 | or =spaceline-workspace-numbers-unicode= to true, respectively.
321 |
322 | Spacemacs also does this with most minor modes. This is a feature that has not
323 | been ported to Spaceline. To do this, use [[https://github.com/emacsmirror/diminish][Diminish]].
324 |
325 | ** Minor modes separator
326 | To configure the separator between the minor modes, use
327 | =spaceline-minor-modes-separator=.
328 |
329 | ** Org clock
330 | The displayed value of the =org-clock= segment is determined by the function
331 | =org-clock-get-clock-string= by default. To configure another function, use
332 | =spaceline-org-clock-format-function=.
333 |
334 | * Deep configuration
335 | To understand how to do this, we must first understand how Spaceline constructs
336 | a mode-line.
337 |
338 | ** Segments
339 | A /segment/ is any part of the mode-line that produces some kind of visible
340 | output. Typically, segments have been defined ahead of time using
341 | =spaceline-define-segment=, in which case the segment is referred to by a
342 | symbol, but segments may also be literals (strings or numbers, say) or lists of
343 | other segments.
344 |
345 | These are all valid segments, provided =my-segment= has been defined:
346 |
347 | #+BEGIN_SRC emacs-lisp
348 | my-segment
349 | "alfa"
350 | (my-segment 89)
351 | #+END_SRC
352 |
353 | Segments may also have properties associated with them. Spaceline supports a
354 | variety of properties. They can be applied as follows, for a ‘singleton’
355 | segment:
356 |
357 | #+BEGIN_SRC emacs-lisp
358 | (my-segment :prop-a value-a :prop-b value-b)
359 | #+END_SRC
360 |
361 | Or for a list of segments:
362 |
363 | #+BEGIN_SRC emacs-lisp
364 | ((my-segment 89)
365 | :prop-a value-a
366 | :prop-b value-b)
367 | #+END_SRC
368 |
369 | ** Defining a segment
370 | Use =spaceline-define-segment= to define a segment and associate it to a symbol.
371 |
372 | #+BEGIN_SRC emacs-lisp
373 | (spaceline-define-segment name
374 | "Docstring"
375 | ;; A single form whose value is the value of the segment.
376 | ;; It may return a string, an image or a list of such.
377 | (when condition
378 | output)
379 |
380 | ;; Additional keyword properties go here
381 | :prop-a value-a
382 | :prop-b value-b)
383 | #+END_SRC
384 |
385 | In addition to storing the segment, this macro produces a variable called
386 | =spaceline-NAME-p= whose value may be set to switch the segment off or on
387 | manually. Three interactive functions are also defined:
388 |
389 | - =spaceline-toggle-NAME=
390 | - =spaceline-toggle-NAME-on=
391 | - =spaceline-toggle-NAME-off=
392 |
393 | These are convenient to bind to keys, and they do what it says on the tin.
394 |
395 | Note that if you redefine a segment, you more than likely have to recompile the
396 | modelines with =M-x spaceline-compile= for the changes to take effect.
397 |
398 | ** Properties
399 | The valid properties are
400 |
401 | - =:priority=: arbitrary number to prioritize which segments are hidden first
402 | when the window shrinks. The higher the number, the higher the priority.
403 | - =:when=: A form that, if it evaluates to =nil=, will prevent the segment from
404 | showing. Note that in =spaceline-define-segment= you might just as well use an
405 | ordinary =when= form. Therefore this only makes sense to use in a segment
406 | spec.
407 | - =:separator=: A separator inserted between each element of the value of the
408 | given segment. This makes most sense for lists of segments, or segments whose
409 | values are typically lists (such as =minor-modes=).
410 | - =:fallback=: A segment which will be displayed in place of the current segment
411 | if it should produce no output (either due to a nil =:when= condition or
412 | because the return value of the segment itself is =nil= or the empty string).
413 | - =:face=: The face in which to render the segment. It may be better to use this
414 | than (or in addition) to propertizing the output directly, since Spaceline
415 | needs to know the faces to propertize the separators correctly. This may be
416 | either =default-face=, =other-face= or =highlight-face=, or a form evaluating
417 | to a face. Thus any face symbol which is not either of the above three must be
418 | quoted.
419 | - =:tight=: Set to =t= to tell Spaceline that the segment should not have any
420 | padding on the right or left. Use =:tight-left= and =:tight-right= for even
421 | finer control.
422 | - =:skip-alternate=: Set to =t= to skip the regular alternating faces for this
423 | segment.
424 |
425 | All of these are valid both in =spaceline-define-segment= as well as directly in
426 | the segment spec, with the excption of =:when=.
427 |
428 | Additionally, =spaceline-define-segment= allows two additional properties.
429 |
430 | - =:enabled=: Sets the initial value of the toggle variable.
431 | - =:global-override=: Many third-party packages provide mode-line information by
432 | inserting a segment in the list =global-mode-string=. Sometimes you might like
433 | to write your own segment for this, in which case you have to prevent the
434 | package from using =global-mode-string=, or you will end up with duplicate
435 | information and a crowded mode-line. To do this, set =:global-override= to the
436 | symbol (or list of symbols) which you want to exclude from
437 | =global-mode-string=. This setting will be honored by the =global= segment,
438 | which is defined by Spaceline core in =spaceline.el=.
439 |
440 | The properties which take effect for any given segment are, in order of
441 | priority:
442 |
443 | - the properties specified in the segment specification
444 | - the properties given in the call to =spaceline-define-segment=
445 | - the properties of the parent segment
446 |
447 | The exceptions are =:when=, which must be true on *all* levels for a segment to
448 | be displayed, and =:fallback= which does *not* pass through from the parent
449 | segment.
450 |
451 | ** Bindings
452 | When evaluating a segment, its =:when= condition or its =:face= property, the
453 | following bindings are available for convenience.
454 |
455 | - =active=: Whether the current window is active or not. Many segments use
456 | =:when active= to only show in the current window.
457 | - =default-face=: The face with which the current segment /should/ be rendered.
458 | If you don’t define a =:face=, this is what you get. For best results, stick
459 | to the default face as often as you can.
460 | - =other-face=: The alternating default face. Spaceline switches =default-face=
461 | and =other-face= for each top-level segment.
462 | - =highlight-face=: The face used to highlight ‘important’ parts, whatever that
463 | may be. This may be customized.
464 | - =line-face=: The face with which the empty part in the middle of the mode-line
465 | will be rendered.
466 |
467 | Note that the segment code runs in an environment with many local variables,
468 | therefore it’s a good idea to write segments as pure functions that do not
469 | change state.
470 |
471 | ** Compiling a mode-line
472 | Finally, call the function =spaceline-compile=. It accepts three arguments: a
473 | modeline name, and two lists of segments, for the left and right sides.
474 |
475 | This produces a function =spaceline-ml-NAME= that evaluates the mode-line. To
476 | use it, set =mode-line-format= to
477 |
478 | #+BEGIN_SRC emacs-lisp
479 | ("%e" (:eval (spaceline-ml-NAME)))
480 | #+END_SRC
481 |
482 | If you do not specify a name, the modeline will be installed as =main=.
483 |
484 | If you do not specify segment lists, it will either recompile the given modeline
485 | with the segments specified last time, or recompile /all/ modelines if the name
486 | is not specified.
487 |
488 | When called interactively, the latter behaviour takes effect, that is, all
489 | modelines are recompiled.
490 |
491 | The variable =spaceline-byte-compile= decides whether the resulting function
492 | will be byte-compiled. This is recommended for regular usage, as it involves
493 | potentially significant performance benefits.
494 |
495 | * Tweaking or defining your own mode-line
496 | To tweak the properties such as =:when= or =:priority= of specific segments,
497 | or having your own selection of segments and order of appearance, you have to
498 | define your own mode-line and =spaceline-compile= it.
499 |
500 | For instance, to use Spacemac's mode-line definition as a starting point to
501 | your own, add this to your =.emacs= or =.spacemacs= and tweak it:
502 |
503 | #+BEGIN_SRC emacs-lisp
504 | (spaceline-compile
505 | ; left side
506 | '(((persp-name
507 | workspace-number
508 | window-number)
509 | :fallback evil-state
510 | :face highlight-face
511 | :priority 100)
512 | (anzu :priority 95)
513 | auto-compile
514 | ((buffer-modified buffer-size buffer-id remote-host)
515 | :priority 98)
516 | (major-mode :priority 79)
517 | (process :when active)
518 | ((flycheck-error flycheck-warning flycheck-info)
519 | :when active
520 | :priority 89)
521 | (minor-modes :when active
522 | :priority 9)
523 | (mu4e-alert-segment :when active)
524 | (erc-track :when active)
525 | (version-control :when active
526 | :priority 78)
527 | (org-pomodoro :when active)
528 | (org-clock :when active)
529 | nyan-cat)
530 | ; right side
531 | '(which-function
532 | (python-pyvenv :fallback python-pyenv)
533 | (purpose :priority 94)
534 | (battery :when active)
535 | (selection-info :priority 95)
536 | input-method
537 | ((buffer-encoding-abbrev
538 | point-position
539 | line-column)
540 | :separator " | "
541 | :priority 96)
542 | (global :when active)
543 | (buffer-position :priority 99)
544 | (hud :priority 99)))
545 | #+END_SRC
546 |
--------------------------------------------------------------------------------
/screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheBB/spaceline/086420d16e526c79b67fc1edec4c2ae1e699f372/screen.png
--------------------------------------------------------------------------------
/spaceline-config.el:
--------------------------------------------------------------------------------
1 | ;;; spaceline-config.el --- Spaceline themes
2 |
3 | ;; This file is not part of GNU Emacs.
4 |
5 | ;; This program is free software; you can redistribute it and/or modify
6 | ;; it under the terms of the GNU General Public License as published by
7 | ;; the Free Software Foundation, either version 3 of the License, or
8 | ;; (at your option) any later version.
9 |
10 | ;; This program is distributed in the hope that it will be useful,
11 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ;; GNU General Public License for more details.
14 |
15 | ;; You should have received a copy of the GNU General Public License
16 | ;; along with this program. If not, see .
17 |
18 | ;;; Commentary:
19 |
20 | ;; This file contains ready-to-use modeline themes for powerline.
21 |
22 | ;;; Code:
23 |
24 | (require 'spaceline-segments)
25 |
26 | (defun spaceline--theme (left second-left &rest additional-segments)
27 | "Convenience function for the spacemacs and emacs themes."
28 | (spaceline-compile
29 | `(,left
30 | (anzu :priority 95)
31 | auto-compile
32 | ,second-left
33 | (major-mode :priority 79)
34 | (process :when active)
35 | ((flycheck-error flycheck-warning flycheck-info)
36 | :when active
37 | :priority 89)
38 | (minor-modes :when active
39 | :priority 9)
40 | (treesit-inspect :when active)
41 | (mu4e-alert-segment :when active)
42 | (erc-track :when active)
43 | (version-control :when active
44 | :priority 78)
45 | (org-pomodoro :when active)
46 | (org-clock :when active)
47 | nyan-cat)
48 | `(which-function
49 | (python-pyvenv :fallback python-pyenv)
50 | (purpose :priority 94)
51 | (battery :when active)
52 | (selection-info :priority 95)
53 | input-method
54 | ((buffer-encoding-abbrev
55 | point-position
56 | line-column)
57 | :separator " | "
58 | :priority 96)
59 | (so-long :when active)
60 | (global :when active)
61 | ,@additional-segments
62 | (buffer-position :priority 99)
63 | (hud :priority 99)))
64 |
65 | (setq-default mode-line-format '("%e" (:eval (spaceline-ml-main)))))
66 |
67 | ;;;###autoload
68 | (defun spaceline-spacemacs-theme (&rest additional-segments)
69 | "Install the modeline used by Spacemacs.
70 |
71 | ADDITIONAL-SEGMENTS are inserted on the right, between `global' and
72 | `buffer-position'."
73 | (apply 'spaceline--theme
74 | '((persp-name
75 | workspace-number
76 | window-number)
77 | :fallback evil-state
78 | :face highlight-face
79 | :priority 100)
80 | '((buffer-modified buffer-size buffer-id remote-host)
81 | :priority 98)
82 | additional-segments))
83 |
84 | ;;;###autoload
85 | (defun spaceline-emacs-theme (&rest additional-segments)
86 | "Install a modeline close to the one used by Spacemacs, but which
87 | looks better without third-party dependencies.
88 |
89 | ADDITIONAL-SEGMENTS are inserted on the right, between `global' and
90 | `buffer-position'."
91 | (apply 'spaceline--theme
92 | '(((((persp-name :fallback workspace-number)
93 | window-number) :separator "|")
94 | buffer-modified
95 | buffer-size)
96 | :face highlight-face
97 | :priority 100)
98 | '((buffer-id remote-host)
99 | :priority 98)
100 | additional-segments))
101 |
102 | ;;; Helm custom mode
103 | ;; ================
104 |
105 | (defvar helm-ag-show-status-function)
106 |
107 | (defun spaceline--helm-ag-update ()
108 | (setq mode-line-format '("%e" (:eval (spaceline-ml-helm-done)))))
109 |
110 | ;;;###autoload
111 | (define-minor-mode spaceline-helm-mode
112 | "Customize the mode-line in helm."
113 | :group 'spaceline
114 | :init-value nil
115 | :global t
116 | (if spaceline-helm-mode
117 | (progn
118 | (spaceline-compile 'helm
119 | '((helm-buffer-id :face highlight-face)
120 | helm-number
121 | helm-follow
122 | helm-prefix-argument)
123 | '(helm-help))
124 | (spaceline-compile 'helm-done
125 | '(((helm-buffer-id helm-done) :face highlight-face)
126 | helm-number
127 | helm-follow
128 | helm-prefix-argument)
129 | '(helm-help))
130 | (defadvice helm-display-mode-line (after spaceline-helm)
131 | "Set up a custom helm modeline."
132 | (setq spaceline--helm-current-source source
133 | mode-line-format '("%e" (:eval (spaceline-ml-helm))))
134 | (when force (force-mode-line-update)))
135 | (setq helm-ag-show-status-function 'spaceline--helm-ag-update)
136 | (ad-activate 'helm-display-mode-line))
137 | (setq helm-ag-show-status-function 'helm-ag-show-status-default-mode-line)
138 | (ad-deactivate 'helm-display-mode-line)))
139 |
140 | ;;; Info custom mode
141 | ;; ================
142 |
143 | ;;;###autoload
144 | (define-minor-mode spaceline-info-mode
145 | "Customize the mode-line in info.
146 | This minor mode requires info+."
147 | :init-value nil
148 | :group 'spaceline
149 | :global t
150 | (if spaceline-info-mode
151 | (progn
152 | (spaceline-compile 'info '(info-topic (info-nodes :separator " > ")) nil)
153 | (defadvice Info-set-mode-line (after spaceline-info)
154 | "Set up a custom info modeline."
155 | (if (featurep 'info+)
156 | (let* ((nodes (s-split " > " mode-line-format))
157 | (topic (prog2
158 | (string-match "(\\(.+\\))\\(.+\\)" (car nodes))
159 | (propertize (concat "INFO "
160 | (match-string 1 (car nodes)))
161 | 'face 'bold)
162 | (setcar nodes (match-string 2 (car nodes))))))
163 | (setq spaceline--info-nodes nodes)
164 | (setq spaceline--info-topic topic)
165 | (setq-local mode-line-format '("%e" (:eval (spaceline-ml-info)))))
166 | (message "info+ is not available: spaceline-info-mode disabled")
167 | (spaceline-info-mode -1)))
168 | (ad-activate 'Info-set-mode-line))
169 | (ad-deactivate 'Info-set-mode-line)))
170 |
171 | (provide 'spaceline-config)
172 |
173 | ;;; spaceline-config.el ends here
174 |
--------------------------------------------------------------------------------
/spaceline-segments.el:
--------------------------------------------------------------------------------
1 | ;;; spaceline-segments.el --- Segments for spaceline
2 |
3 | ;; This file is not part of GNU Emacs.
4 |
5 | ;; This program is free software; you can redistribute it and/or modify
6 | ;; it under the terms of the GNU General Public License as published by
7 | ;; the Free Software Foundation, either version 3 of the License, or
8 | ;; (at your option) any later version.
9 |
10 | ;; This program is distributed in the hope that it will be useful,
11 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | ;; GNU General Public License for more details.
14 |
15 | ;; You should have received a copy of the GNU General Public License
16 | ;; along with this program. If not, see .
17 |
18 | ;;; Commentary:
19 |
20 | ;; This file contains a variety of segments that may be of general interest in
21 | ;; many people's modelines. It contains both "stock" segments which are usable
22 | ;; without any additional packages, as well as a number of segments which depend
23 | ;; on optional third-party packages.
24 |
25 | ;; Note: The `global' segment is defined in spaceline.el, not here. It's the
26 | ;; only exception.
27 |
28 | ;;; Code:
29 |
30 | (require 'spaceline)
31 | (require 's)
32 |
33 | (defvar evil-state)
34 | (defvar evil-visual-selection)
35 |
36 | ;;; Stock segments - no optional dependencies
37 | ;; =========================================
38 |
39 | (defvar spaceline-minor-modes-separator "|")
40 | (spaceline-define-segment minor-modes
41 | "A list of minor modes. Configure the separator with
42 | `spaceline-minor-modes-separator'."
43 | (-filter
44 | (lambda (k) (and k (not (string= k ""))))
45 | (mapcar (lambda (mm)
46 | (let* ((displayp (and (boundp (car mm))
47 | (symbol-value (car mm))))
48 | (lighter (when displayp
49 | (s-trim (format-mode-line (cadr mm)))))
50 | (displayp (and lighter (not (string= "" lighter)))))
51 | (when displayp
52 | (propertize
53 | lighter
54 | 'mouse-face 'mode-line-highlight
55 | 'help-echo (concat (symbol-name (car mm))
56 | "\nmouse-1: Display minor mode menu"
57 | "\nmouse-2: Show help for minor mode"
58 | "\nmouse-3: Toggle minor mode")
59 | 'local-map (let ((map (make-sparse-keymap)))
60 | (define-key map
61 | [mode-line mouse-1]
62 | (powerline-mouse 'minor 'menu lighter))
63 | (define-key map
64 | [mode-line mouse-2]
65 | (powerline-mouse 'minor 'help lighter))
66 | (define-key map
67 | [mode-line mouse-3]
68 | (powerline-mouse 'minor 'menu lighter))
69 | (define-key map
70 | [header-line down-mouse-3]
71 | (powerline-mouse 'minor 'menu lighter))
72 | map)))))
73 | minor-mode-alist))
74 | :separator spaceline-minor-modes-separator)
75 |
76 | (spaceline-define-segment buffer-modified
77 | "Buffer modified marker."
78 | "%*")
79 |
80 | (spaceline-define-segment buffer-size
81 | "Size of buffer."
82 | (if (bound-and-true-p total-lines-mode)
83 | (format "%d" total-lines)
84 | (powerline-buffer-size)))
85 |
86 | (defcustom spaceline-buffer-id-max-length 45
87 | "The maximum displayed length of the buffer-id segment."
88 | :type 'integer
89 | :group 'spaceline)
90 |
91 | (spaceline-define-segment buffer-id
92 | "Name of buffer."
93 | (spaceline--string-trim-from-center
94 | (s-trim (powerline-buffer-id (if active 'mode-line-buffer-id 'mode-line-buffer-id-inactive)))
95 | spaceline-buffer-id-max-length))
96 |
97 | (spaceline-define-segment remote-host
98 | "Hostname for remote buffers."
99 | (when (and default-directory
100 | (file-remote-p default-directory 'host))
101 | (concat "@" (file-remote-p default-directory 'host))))
102 |
103 | (spaceline-define-segment major-mode
104 | "The name of the major mode."
105 | (powerline-major-mode))
106 |
107 | (spaceline-define-segment process
108 | "The process associated with this buffer, if any."
109 | (when (spaceline--mode-line-nonempty mode-line-process)
110 | (s-trim (powerline-raw mode-line-process))))
111 |
112 | (spaceline-define-segment version-control-simple
113 | "Simplified version control information."
114 | (when vc-mode
115 | (powerline-raw
116 | (when (buffer-file-name)
117 | (pcase (vc-state (buffer-file-name))
118 | (`up-to-date " ")
119 | (`ignored " ")
120 | (`edited "~")
121 | (`added "+")
122 | (`removed "-")
123 | (`needs-merge "!")
124 | (`needs-update "!")
125 | (_ "?"))))))
126 |
127 | (spaceline-define-segment version-control
128 | "Version control information."
129 | (when vc-mode
130 | (powerline-raw
131 | (s-trim (concat vc-mode
132 | (when (buffer-file-name)
133 | (pcase (vc-state (buffer-file-name))
134 | (`up-to-date " ")
135 | (`edited " Mod")
136 | (`added " Add")
137 | (`unregistered " ??")
138 | (`removed " Del")
139 | (`needs-merge " Con")
140 | (`needs-update " Upd")
141 | (`ignored " Ign")
142 | (_ " Unk"))))))))
143 |
144 | (spaceline-define-segment buffer-encoding
145 | "The full `buffer-file-coding-system'."
146 | (format "%s" buffer-file-coding-system))
147 |
148 | (spaceline-define-segment buffer-encoding-abbrev
149 | "The line ending convention used in the buffer."
150 | (let ((buf-coding (format "%s" buffer-file-coding-system)))
151 | (if (string-match "\\(dos\\|unix\\|mac\\)" buf-coding)
152 | (match-string 1 buf-coding)
153 | buf-coding)))
154 |
155 | (spaceline-define-segment point-position
156 | "The value of `(point)'."
157 | (format "%d" (point))
158 | :enabled nil)
159 |
160 | (spaceline-define-segment line
161 | "The current line number."
162 | "%l")
163 |
164 | (spaceline-define-segment column
165 | "The current column number."
166 | (if (and
167 | (boundp 'column-number-indicator-zero-based)
168 | (not column-number-indicator-zero-based))
169 | "%2C"
170 | "%2c"))
171 |
172 | (defun spaceline--docview-page-number ()
173 | "The current `doc-view-mode' page number to display in the mode-line.
174 | Return a formated string containing the current and last page number for the
175 | currently displayed pdf file in `doc-view-mode'."
176 | (format "(%d/%d)"
177 | (image-mode-window-get 'page nil)
178 | (doc-view-last-page-number)))
179 |
180 | (declare-function pdf-view-current-page 'pdf-view)
181 | (declare-function pdf-cache-number-of-pages 'pdf-view)
182 |
183 | (defun spaceline--pdfview-page-number ()
184 | "The current `pdf-view-mode' page number to display in the mode-line.
185 | Return a formated string containing the current and last page number for the
186 | currently displayed pdf file in `pdf-view-mode'."
187 | (format "(%d/%d)"
188 | ;; `pdf-view-current-page' is a macro in an optional dependency
189 | ;; any better solutions?
190 | (eval `(pdf-view-current-page))
191 | (pdf-cache-number-of-pages)))
192 |
193 | (spaceline-define-segment line-column
194 | "The current line and column numbers, or `(current page/number of pages)`
195 | in pdf-view mode (enabled by the `pdf-tools' package)."
196 | (cond ((eq major-mode 'doc-view-mode)
197 | (spaceline--docview-page-number))
198 | ((eq major-mode 'pdf-view-mode)
199 | (spaceline--pdfview-page-number))
200 | (t (if (and
201 | (boundp 'column-number-indicator-zero-based)
202 | (not column-number-indicator-zero-based))
203 | "%l:%2C"
204 | "%l:%2c"))))
205 |
206 | (spaceline-define-segment buffer-position
207 | "The current approximate buffer position, in percent."
208 | "%p")
209 |
210 | (defun spaceline--column-number-at-pos (pos)
211 | "Column number at POS. Analog to `line-number-at-pos'."
212 | (save-excursion (goto-char pos) (current-column)))
213 |
214 | (spaceline-define-segment selection-info
215 | "Information about the size of the current selection, when applicable.
216 | Supports both Emacs and Evil cursor conventions."
217 | (when (or mark-active
218 | (and (bound-and-true-p evil-local-mode)
219 | (eq 'visual evil-state)))
220 | (let* ((lines (count-lines (region-beginning) (min (1+ (region-end)) (point-max))))
221 | (chars (- (1+ (region-end)) (region-beginning)))
222 | (cols (1+ (abs (- (spaceline--column-number-at-pos (region-end))
223 | (spaceline--column-number-at-pos (region-beginning))))))
224 | (evil (and (bound-and-true-p evil-state) (eq 'visual evil-state)))
225 | (rect (or (bound-and-true-p rectangle-mark-mode)
226 | (and evil (eq 'block evil-visual-selection))))
227 | (multi-line (or (> lines 1) (and evil (eq 'line evil-visual-selection)))))
228 | (cond
229 | (rect (format "%d×%d block" lines (if evil cols (1- cols))))
230 | (multi-line (format "%d lines" lines))
231 | (t (format "%d chars" (if evil chars (1- chars))))))))
232 |
233 | (defcustom spaceline-show-default-input-method nil
234 | "Whether to show the default input method in `input-method'.
235 |
236 | When non-nil, show the default input method in the `input-method'
237 | segment. Otherwise only show the active input method, if any."
238 | :type 'boolean
239 | :group 'spaceline
240 | :risky t)
241 |
242 | (spaceline-define-segment input-method
243 | "The current input method, or the default input method."
244 | (when (or current-input-method
245 | (and (bound-and-true-p evil-mode)
246 | (bound-and-true-p evil-input-method))
247 | (and spaceline-show-default-input-method
248 | default-input-method))
249 | (cond
250 | (current-input-method
251 | (propertize current-input-method-title 'face 'bold))
252 | ;; `evil-input-method' is where evil remembers the input method while in
253 | ;; normal state. The input method is not active in normal state, but Evil
254 | ;; will enable this input method again when switching to insert/emacs state.
255 | ((and (bound-and-true-p evil-mode) (bound-and-true-p evil-input-method))
256 | (nth 3 (assoc default-input-method input-method-alist)))
257 | ((and spaceline-show-default-input-method default-input-method)
258 | (propertize (nth 3 (assoc default-input-method input-method-alist))
259 | 'face 'italic)))))
260 |
261 | (spaceline-define-segment hud
262 | "A HUD that shows which part of the buffer is currently visible."
263 | (powerline-hud highlight-face default-face)
264 | :tight t)
265 |
266 | ;;; Helm segments
267 | ;; =============
268 |
269 | (declare-function helm-candidate-number-at-point 'helm)
270 | (declare-function helm-get-candidate-number 'helm)
271 |
272 | (defvar spaceline--helm-buffer-ids
273 | '(("*helm*" . "HELM")
274 | ("*helm M-x*" . "HELM M-x")
275 | ("*swiper*" . "SWIPER")
276 | ("*Projectile Perspectives*" . "HELM Projectile Perspectives")
277 | ("*Projectile Layouts*" . "HELM Projectile Layouts")
278 | ("*helm-ag*" . (lambda ()
279 | (format "HELM Ag: Using %s"
280 | (car (split-string helm-ag-base-command))))))
281 | "Alist of custom helm buffer names to use.
282 | The cdr can also be a function that returns a name to use.")
283 | (spaceline-define-segment helm-buffer-id
284 | "Helm session identifier."
285 | (when (bound-and-true-p helm-alive-p)
286 | (propertize
287 | (let ((custom (cdr (assoc (buffer-name) spaceline--helm-buffer-ids)))
288 | (case-fold-search t)
289 | (name (replace-regexp-in-string "-" " " (buffer-name))))
290 | (cond ((stringp custom) custom)
291 | ((functionp custom) (funcall custom))
292 | (t
293 | (string-match "\\*helm:? \\(mode \\)?\\([^\\*]+\\)\\*" name)
294 | (concat "HELM " (capitalize (match-string 2 name))))))
295 | 'face 'bold)))
296 |
297 | (spaceline-define-segment helm-done
298 | "Done."
299 | (propertize "(DONE)" 'face 'bold))
300 |
301 | (spaceline-define-segment helm-number
302 | "Number of helm candidates."
303 | (when (bound-and-true-p helm-alive-p)
304 | (format "%d/%s (%s total)"
305 | (helm-candidate-number-at-point)
306 | (helm-get-candidate-number t)
307 | (helm-get-candidate-number))))
308 |
309 | (spaceline-define-segment helm-help
310 | "Helm keybindings help."
311 | (when (bound-and-true-p helm-alive-p)
312 | (-interleave
313 | (mapcar (lambda (s)
314 | (propertize (substitute-command-keys s) 'face 'bold))
315 | '("\\\\[helm-help]"
316 | "\\\\[helm-select-action]"
317 | "\\\\[helm-maybe-exit-minibuffer]/F1/F2..."))
318 | '("(help)" "(actions)" "(action)"))))
319 |
320 | (spaceline-define-segment helm-prefix-argument
321 | "Helm prefix argument."
322 | (when (and (bound-and-true-p helm-alive-p)
323 | helm--mode-line-display-prefarg)
324 | (let ((arg (prefix-numeric-value (or prefix-arg current-prefix-arg))))
325 | (unless (= arg 1)
326 | (propertize (format "C-u %s" arg) 'face 'helm-prefarg)))))
327 |
328 | (defvar spaceline--helm-current-source nil
329 | "The currently active helm source.")
330 | (spaceline-define-segment helm-follow
331 | "Helm follow indicator."
332 | (when (and (bound-and-true-p helm-alive-p)
333 | spaceline--helm-current-source
334 | (eq 1 (cdr (assq 'follow spaceline--helm-current-source))))
335 | "HF"))
336 |
337 | ;;; Info segments
338 | ;; =============
339 |
340 | (defvar spaceline--info-topic nil
341 | "Topic for the info modeline.")
342 | (spaceline-define-segment info-topic
343 | "Topic for the info modeline."
344 | spaceline--info-topic)
345 | (defvar spaceline--info-nodes nil
346 | "Breadcrumbs for the info modeline.")
347 | (spaceline-define-segment info-nodes
348 | "Breadcrumbs for the info modeline."
349 | spaceline--info-nodes)
350 |
351 | ;;; Segments requiring optional dependencies
352 | ;; ========================================
353 |
354 | (defvar conda-env-current-name)
355 | (defvar erc-modified-channels-object)
356 | (defvar erc-track-position-in-mode-line)
357 | (defvar fancy-battery-last-status)
358 | (defvar fancy-battery-show-percentage)
359 | (defvar mu4e-alert-mode-line)
360 | (defvar org-pomodoro-mode-line)
361 | (defvar pyvenv-virtual-env)
362 | (defvar pyvenv-virtual-env-name)
363 | (defvar which-func-current)
364 | (defvar which-func-keymap)
365 |
366 | (declare-function projectile-project-name 'projectile)
367 | (declare-function anzu--update-mode-line 'anzu)
368 | (declare-function evil-state-property 'evil-common)
369 | (declare-function eyebrowse--get 'eyebrowse)
370 | (declare-function mode-line-auto-compile-control 'auto-compile)
371 | (declare-function nyan-create 'nyan-mode)
372 | (declare-function safe-persp-name 'persp-mode)
373 | (declare-function get-frame-persp 'persp-mode)
374 | (declare-function winum-get-number 'winum)
375 | (declare-function window-numbering-get-number 'window-numbering)
376 | (declare-function purpose--modeline-string 'window-purpose)
377 | (declare-function purpose-window-purpose-dedicated-p 'window-purpose)
378 | (declare-function pyenv-mode-version 'pyenv-mode)
379 | (declare-function pyenv-mode-full-path 'pyenv-mode)
380 | (declare-function doc-view-last-page-number 'doc-view)
381 | (declare-function image-mode-window-get 'image-mode)
382 |
383 | (spaceline-define-segment projectile-root
384 | "Show the current projectile root."
385 | (when (fboundp 'projectile-project-name)
386 | (let ((project-name (projectile-project-name)))
387 | (unless (or (string= project-name "-")
388 | (string= project-name (buffer-name)))
389 | project-name))))
390 |
391 | (spaceline-define-segment anzu
392 | "Show the current match number and the total number of matches.
393 | Requires anzu to be enabled."
394 | (when (and active (bound-and-true-p anzu--state))
395 | (anzu--update-mode-line)))
396 |
397 | (spaceline-define-segment auto-compile
398 | "Show the count of byte-compiler warnings from the auto-compile
399 | package."
400 | (when (and active (boundp 'auto-compile-warnings) (> auto-compile-warnings 0))
401 | (mode-line-auto-compile-control)))
402 |
403 | (spaceline-define-segment erc-track
404 | "Show the ERC buffers with new messages. Requires
405 | `erc-track-mode' to be enabled and
406 | `erc-track-position-in-mode-line' to be set to true."
407 | (when (and (bound-and-true-p erc-track-mode)
408 | erc-track-position-in-mode-line
409 | erc-modified-channels-object)
410 | (s-trim erc-modified-channels-object))
411 | :global-override erc-modified-channels-object)
412 |
413 | (defun spaceline--fancy-battery-percentage ()
414 | "Return the load percentage or an empty string."
415 | (let ((p (cdr (assq ?p fancy-battery-last-status))))
416 | (if (and fancy-battery-show-percentage
417 | p (not (string= "N/A" p))) (concat " " p "%%") "")))
418 |
419 | (defun spaceline--fancy-battery-time ()
420 | "Return the remaining time complete load or discharge."
421 | (let ((time (cdr (assq ?t fancy-battery-last-status))))
422 | (cond
423 | ((string= "0:00" time) "")
424 | ((string= "N/A" time) "")
425 | ((string= time "") "")
426 | (t (concat " (" time ")")))))
427 |
428 | (defun spaceline--fancy-battery-mode-line ()
429 | "Assemble a mode line string for Fancy Battery Mode."
430 | (when fancy-battery-last-status
431 | (let* ((type (cdr (assq ?L fancy-battery-last-status)))
432 | (percentage (spaceline--fancy-battery-percentage))
433 | (time (spaceline--fancy-battery-time)))
434 | (cond
435 | ((string= "on-line" type) " No Battery")
436 | ((string= type "") " No Battery")
437 | (t (concat (if (string= "AC" type) " AC" "") percentage time))))))
438 |
439 | (defun spaceline--fancy-battery-face ()
440 | "Return a face appropriate for powerline."
441 | (let ((type (cdr (assq ?L fancy-battery-last-status))))
442 | (if (and type (string= "AC" type))
443 | 'fancy-battery-charging
444 | (pcase (cdr (assq ?b fancy-battery-last-status))
445 | ("!" 'fancy-battery-critical)
446 | ("+" 'fancy-battery-charging)
447 | ("-" 'fancy-battery-discharging)
448 | (_ 'fancy-battery-discharging)))))
449 |
450 | (spaceline-define-segment battery
451 | "Show battery information. Requires `fancy-battery-mode' to be enabled.
452 |
453 | This segment overrides the modeline functionality of
454 | `fancy-battery-mode'."
455 | (when (bound-and-true-p fancy-battery-mode)
456 | (let ((text (spaceline--fancy-battery-mode-line)))
457 | (and text (powerline-raw (s-trim text)
458 | (spaceline--fancy-battery-face)))))
459 | :global-override fancy-battery-mode-line)
460 |
461 | (defvar spaceline-org-clock-format-function
462 | 'org-clock-get-clock-string
463 | "The function called by the `org-clock' segment to determine what to show.")
464 |
465 | (spaceline-define-segment org-clock
466 | "Show information about the current org clock task. Configure
467 | `spaceline-org-clock-format-function' to configure. Requires a currently running
468 | org clock.
469 |
470 | This segment overrides the modeline functionality of `org-mode-line-string'."
471 | (when (and (fboundp 'org-clocking-p)
472 | (org-clocking-p))
473 | (substring-no-properties (funcall spaceline-org-clock-format-function)))
474 | :global-override org-mode-line-string)
475 |
476 | (spaceline-define-segment org-pomodoro
477 | "Shows the current pomodoro. Requires `org-pomodoro' to be active.
478 |
479 | This segment overrides the modeline functionality of `org-pomodoro' itself."
480 | (when (and (fboundp 'org-pomodoro-active-p)
481 | (org-pomodoro-active-p))
482 | (nth 1 org-pomodoro-mode-line))
483 | :global-override org-pomodoro-mode-line)
484 |
485 | (spaceline-define-segment nyan-cat
486 | "Shows the infamous nyan cat. Requires `nyan-mode' to be enabled."
487 | (when (bound-and-true-p nyan-mode)
488 | (powerline-raw (nyan-create) default-face)))
489 |
490 | (defun spaceline--unicode-number (str)
491 | "Return a nice unicode representation of a single-digit number STR."
492 | (cond
493 | ((string= "1" str) "➊")
494 | ((string= "2" str) "➋")
495 | ((string= "3" str) "➌")
496 | ((string= "4" str) "➍")
497 | ((string= "5" str) "➎")
498 | ((string= "6" str) "➏")
499 | ((string= "7" str) "➐")
500 | ((string= "8" str) "➑")
501 | ((string= "9" str) "➒")
502 | ((string= "10" str) "➓")
503 | (t str)))
504 |
505 | (defvar spaceline-window-numbers-unicode nil
506 | "Set to true to enable unicode display in the `window-number' segment.")
507 |
508 | (spaceline-define-segment window-number
509 | "The current window number.
510 | Requires either `winum-mode' or `window-numbering-mode' to be enabled."
511 | (let* ((num (cond
512 | ((bound-and-true-p winum-mode)
513 | (winum-get-number))
514 | ((bound-and-true-p window-numbering-mode)
515 | (window-numbering-get-number))
516 | (t nil)))
517 | (str (when num (int-to-string num))))
518 | (when num
519 | (if spaceline-window-numbers-unicode
520 | (spaceline--unicode-number str)
521 | (propertize str 'face 'bold)))))
522 |
523 | (defvar spaceline-workspace-numbers-unicode nil
524 | "Set to true to enable unicode display in the `workspace-number' segment.")
525 |
526 | (spaceline-define-segment workspace-number
527 | "The current workspace name or number. Requires `eyebrowse-mode' to be
528 | enabled."
529 | (when (and (bound-and-true-p eyebrowse-mode)
530 | (< 1 (length (eyebrowse--get 'window-configs))))
531 | (let* ((num (eyebrowse--get 'current-slot))
532 | (tag (when num (nth 2 (assoc num (eyebrowse--get 'window-configs)))))
533 | (str (if (and tag (< 0 (length tag)))
534 | tag
535 | (when num (int-to-string num)))))
536 | (or (when spaceline-workspace-numbers-unicode
537 | (spaceline--unicode-number str))
538 | (propertize str 'face 'bold)))))
539 |
540 | (defvar spaceline-display-default-perspective nil
541 | "If non-nil, the default perspective name is displayed in the mode-line.")
542 |
543 | (spaceline-define-segment persp-name
544 | "The current perspective name."
545 | (when (and active
546 | (bound-and-true-p persp-mode)
547 | ;; There are multiple implementations of
548 | ;; persp-mode with different APIs
549 | (fboundp 'safe-persp-name)
550 | (fboundp 'get-frame-persp)
551 | ;; Display the nil persp only if specified
552 | (or (not (string= persp-nil-name (safe-persp-name (get-frame-persp))))
553 | spaceline-display-default-perspective))
554 | (let ((name (safe-persp-name (get-frame-persp))))
555 | (propertize
556 | (if (file-directory-p name)
557 | (file-name-nondirectory (directory-file-name name))
558 | name)
559 | 'face 'bold))))
560 |
561 | (defface spaceline-flycheck-error
562 | '((t (:foreground "#FC5C94" :distant-foreground "#A20C41")))
563 | "Face for flycheck error feedback in the modeline."
564 | :group 'spaceline)
565 | (defface spaceline-flycheck-warning
566 | '((t (:foreground "#F3EA98" :distant-foreground "#968B26")))
567 | "Face for flycheck warning feedback in the modeline."
568 | :group 'spaceline)
569 | (defface spaceline-flycheck-info
570 | '((t (:foreground "#8DE6F7" :distant-foreground "#21889B")))
571 | "Face for flycheck info feedback in the modeline."
572 | :group 'spaceline)
573 |
574 | (defvar spaceline-flycheck-bullet "•%s"
575 | "The bullet used for the flycheck segment.
576 | This should be a format string with a single `%s'-expression corresponding to
577 | the number of errors.")
578 |
579 | (defmacro spaceline--flycheck-lighter (state)
580 | "Return flycheck information for the given error type STATE."
581 | `(let* ((counts (flycheck-count-errors flycheck-current-errors))
582 | (errorp (flycheck-has-current-errors-p ',state))
583 | (err (or (cdr (assq ',state counts)) "?"))
584 | (running (eq 'running flycheck-last-status-change)))
585 | (if (or errorp running) (format spaceline-flycheck-bullet err))))
586 |
587 | (dolist (state '(error warning info))
588 | (let ((segment-name (intern (format "flycheck-%S" state)))
589 | (face (intern (format "spaceline-flycheck-%S" state))))
590 | (eval
591 | `(spaceline-define-segment ,segment-name
592 | ,(format "Information about flycheck %Ss. Requires `flycheck-mode' to be enabled" state)
593 | (when (and (bound-and-true-p flycheck-mode)
594 | (or flycheck-current-errors
595 | (eq 'running flycheck-last-status-change)))
596 | (let ((lighter (spaceline--flycheck-lighter ,state)))
597 | (when lighter (powerline-raw (s-trim lighter) ',face))))))))
598 |
599 | (spaceline-define-segment evil-state
600 | "The current evil state. Requires `evil-mode' to be enabled."
601 | (when (bound-and-true-p evil-local-mode)
602 | (let ((tag (evil-state-property evil-state :tag t)))
603 | (s-trim (if (stringp tag) tag (funcall tag))))))
604 |
605 | (defface spaceline-python-venv
606 | '((t (:foreground "plum1" :distant-foreground "DarkMagenta")))
607 | "Face for highlighting the python venv."
608 | :group 'spaceline)
609 |
610 | (defvar spaceline-purpose-hide-if-not-dedicated nil
611 | "Hide the purpose segment if the window is not dedicated in
612 | some way.")
613 |
614 | (spaceline-define-segment purpose
615 | "The current window purpose. Requires `purpose-mode' to be
616 | enabled."
617 | (when (and (bound-and-true-p purpose-mode)
618 | (or (not spaceline-purpose-hide-if-not-dedicated)
619 | (purpose-window-purpose-dedicated-p)
620 | (window-dedicated-p)))
621 | (propertize (substring (purpose--modeline-string) 2 -1)
622 | 'face 'spaceline-python-venv
623 | 'help-echo "Window purpose")))
624 |
625 | (spaceline-define-segment python-env
626 | "The current python env. Works with `pyvenv', `pyenv' and `conda'."
627 | (when (and active (eq 'python-mode major-mode))
628 | (let (name source)
629 | (cond
630 | ((bound-and-true-p pyvenv-virtual-env-name)
631 | (setq name pyvenv-virtual-env-name source "pyvenv"))
632 | ((bound-and-true-p conda-env-current-name)
633 | (setq name conda-env-current-name source "conda"))
634 | ((and (fboundp 'pyenv-mode) (setq name (pyenv-mode-version)))
635 | (setq source "pyenv")))
636 | (when name
637 | (propertize name
638 | 'face 'spaceline-python-venv
639 | 'help-echo (format "Virtual environment (via %s): %s" source name))))))
640 |
641 | (spaceline-define-segment python-pyvenv
642 | "The current python venv. Works with `pyvenv'."
643 | (when (and active
644 | (eq 'python-mode major-mode)
645 | (bound-and-true-p pyvenv-virtual-env-name))
646 | (propertize pyvenv-virtual-env-name
647 | 'face 'spaceline-python-venv
648 | 'help-echo (format "Virtual environment (via pyvenv): %s"
649 | pyvenv-virtual-env))))
650 |
651 | (spaceline-define-segment python-pyenv
652 | "The current python venv. Works with `pyenv'."
653 | (when (and active
654 | (eq 'python-mode major-mode)
655 | (fboundp 'pyenv-mode-version)
656 | (pyenv-mode-version))
657 | (let ((name (pyenv-mode-version)))
658 | (propertize name
659 | 'face 'spaceline-python-venv
660 | 'help-echo "Virtual environment (via pyenv)"))))
661 |
662 | (spaceline-define-segment paradox-menu
663 | "The current package info including upgradable, new, installed
664 | and total packages"
665 | (when (and active (derived-mode-p 'paradox-menu-mode))
666 | mode-line-buffer-identification))
667 |
668 | (spaceline-define-segment which-function
669 | (when (and active
670 | (bound-and-true-p which-function-mode)
671 | (bound-and-true-p which-func-mode))
672 | (let* ((current (format-mode-line which-func-current)))
673 | (when (string-match "{\\(.*\\)}" current)
674 | (setq current (match-string 1 current)))
675 | (setq current (replace-regexp-in-string "%" "%%" current))
676 | (propertize current
677 | 'local-map which-func-keymap
678 | 'face 'which-func
679 | 'mouse-face 'mode-line-highlight
680 | 'help-echo "mouse-1: go to beginning\n\
681 | mouse-2: toggle rest visibility\n\
682 | mouse-3: go to end"))))
683 |
684 | (spaceline-define-segment mu4e-alert-segment
685 | "Show the number of unread mails using mu. Requires mu4e-alert"
686 | (when (and active (featurep 'mu4e-alert))
687 | mu4e-alert-mode-line)
688 | :global-override ((:eval mu4e-alert-mode-line)))
689 |
690 | (spaceline-define-segment recursive-edit
691 | "Shows the current recursive-edit depth."
692 | (format "↻%s" (recursion-depth))
693 | :when (> (recursion-depth) 0))
694 |
695 | (spaceline-define-segment macrodef
696 | "Shows when defining a keyboard macro."
697 | "•REC"
698 | :when defining-kbd-macro)
699 |
700 | (spaceline-define-segment treesit-inspect
701 | "Show tree-sitter node at point."
702 | (when (and active
703 | (fboundp 'treesit-available-p)
704 | (treesit-available-p)
705 | (bound-and-true-p treesit-inspect-mode))
706 | '((:eval treesit--inspect-name))))
707 |
708 | (spaceline-define-segment so-long
709 | "Show `so-long-mode-line-info'."
710 | (when (and active
711 | (bound-and-true-p so-long-mode-line-info))
712 | '(("" so-long-mode-line-info))))
713 |
714 | (provide 'spaceline-segments)
715 |
716 | ;;; spaceline-segments.el ends here
717 |
--------------------------------------------------------------------------------
/spaceline.el:
--------------------------------------------------------------------------------
1 | ;;; spaceline.el --- Modeline configuration library for powerline
2 |
3 | ;; Copyright (C) 2015 TheBB
4 | ;;
5 | ;; Author: Eivind Fonn
6 | ;; URL: https://github.com/TheBB/spaceline
7 | ;; Version: 2.0.1
8 | ;; Keywords: mode-line powerline spacemacs
9 | ;; Package-Requires: ((emacs "24.4") (cl-lib "0.5") (powerline "2.3") (dash "2.11.0") (s "1.10.0"))
10 |
11 | ;; This file is not part of GNU Emacs.
12 |
13 | ;; This program is free software; you can redistribute it and/or modify
14 | ;; it under the terms of the GNU General Public License as published by
15 | ;; the Free Software Foundation, either version 3 of the License, or
16 | ;; (at your option) any later version.
17 |
18 | ;; This program is distributed in the hope that it will be useful,
19 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | ;; GNU General Public License for more details.
22 |
23 | ;; You should have received a copy of the GNU General Public License
24 | ;; along with this program. If not, see .
25 |
26 | ;;; Commentary:
27 |
28 | ;; Spaceline is a modular mode-line library built on the powerline package,
29 | ;; designed to make it easy to build beautiful mode-lines.
30 | ;;
31 | ;; It was originally used in the Spacemacs distribution, but has since been
32 | ;; extracted as a stand-alone package.
33 |
34 | ;;; Code:
35 |
36 | (require 'dash)
37 | (require 'gv)
38 | (require 'powerline)
39 | (require 'cl-lib)
40 | (require 'subr-x)
41 |
42 | (defvar evil-previous-state)
43 | (defvar evil-state)
44 | (defvar evil-visual-selection)
45 |
46 | (defvar spaceline-byte-compile t
47 | "Whether to byte compile the modeline.")
48 |
49 | (defvar spaceline-responsive t
50 | "If true, the modeline responds to narrow windows by
51 | dynamically hiding segments.")
52 |
53 | (defvar spaceline--mode-lines nil
54 | "Alist of modelines.
55 | Each CAR is a symbol naming the modeline, and the CDR is a cons
56 | cell (LEFT . RIGHT) where LEFT and RIGHT are lists of segments.
57 | See `spaceline-compile' for a description of segments.")
58 |
59 | (defvar spaceline-inflation nil
60 | "A factor by which to artificially pad the modeline. Note that
61 | this does not currently also impact the size of the powerline
62 | separators. Those must be set separately.")
63 |
64 | (defvar spaceline-pre-hook nil
65 | "Hook run before the modeline is rendered.")
66 |
67 | (defvar spaceline-separator-dir-left nil
68 | "The separator directions to use for the left side.
69 | Cons of the form (DIR . DIR) where DIR is one of left and right,
70 | or nil, in which case the best separators are chosen depending on
71 | the separator style.")
72 |
73 | (defvar spaceline-separator-dir-right nil
74 | "The separator directions to use for the right side.
75 | Cons of the form (DIR . DIR) where DIR is one of left and right,
76 | or nil, in which case the best separators are chosen depending on
77 | the separator style.")
78 |
79 | (defvar spaceline-directed-separators '(arrow arrow-fade brace butt curve roundstub utf-8)
80 | "List of directed powerline separators.
81 | Unless the directions are explicitly set in
82 | `spaceline-separator-dir-left' or
83 | `spaceline-separator-dir-right', these are the separators for
84 | which Spaceline will choose different directions on the left and
85 | right sides.")
86 |
87 | (defvar spaceline-highlight-face-func 'spaceline-highlight-face-default
88 | "The function that decides the highlight face.
89 | Superseded by `spaceline-face-func' if that variable is set.")
90 |
91 | (defvar spaceline-face-func nil
92 | "The function that defines all faces.
93 | Must be a function that accepts two arguments: FACE and ACTIVE,
94 | where FACE is `face1', `face2' `line' or `highlight', and ACTIVE
95 | determines whether the window in question is active. It should
96 | return a face to use.
97 |
98 | This variable supersedes `spaceline-highlight-face-func' if set.")
99 |
100 | (defvar spaceline-always-show-segments nil
101 | "When true, show all the segments that would otherwise be
102 | hidden in inactive windows.")
103 |
104 | (defun spaceline--get-separator-dirs (side)
105 | "Gets the preconfigured separator directions for SIDE, or the \"best\" ones,
106 | if not specified."
107 | (or (if (eq 'l side)
108 | spaceline-separator-dir-left
109 | spaceline-separator-dir-right)
110 | (cond
111 | ((memq powerline-default-separator spaceline-directed-separators)
112 | (if (eq 'l side) '(left . left) '(right . right)))
113 | (t '(left . right)))))
114 |
115 | (defun spaceline--get-face (face active)
116 | "Universal function to get the right face.
117 | FACE and ACTIVE have the same meanings as in
118 | `spaceline-face-func'. It delegates the work to
119 | `spaceline-face-func' if it is given, otherwise falls back to
120 | default configuration."
121 | (if spaceline-face-func
122 | (funcall spaceline-face-func face active)
123 | (cond
124 | ((eq 'face1 face) (if active 'powerline-active1 'powerline-inactive1))
125 | ((eq 'face2 face) (if active 'mode-line 'mode-line-inactive))
126 | ((eq 'line face) (if active 'powerline-active2 'powerline-inactive2))
127 | ((eq 'highlight face) (if active
128 | (funcall spaceline-highlight-face-func)
129 | 'powerline-inactive1)))))
130 |
131 | (defface spaceline-highlight-face
132 | `((t (:background "DarkGoldenrod2"
133 | :foreground "#3E3D31"
134 | :inherit 'mode-line)))
135 | "Default highlight face for spaceline."
136 | :group 'spaceline)
137 |
138 | ;; Define various other highlight faces
139 | (dolist (s '((spaceline-evil-normal "DarkGoldenrod2" "Evil normal state face.")
140 | (spaceline-evil-insert "chartreuse3" "Evil insert state face.")
141 | (spaceline-evil-emacs "SkyBlue2" "Evil emacs state face.")
142 | (spaceline-evil-replace "chocolate" "Evil replace state face.")
143 | (spaceline-evil-visual "gray" "Evil visual state face.")
144 | (spaceline-evil-motion "plum3" "Evil motion state face.")
145 | (spaceline-unmodified "DarkGoldenrod2" "Unmodified buffer face.")
146 | (spaceline-modified "SkyBlue2" "Modified buffer face.")
147 | (spaceline-read-only "plum3" "Read-only buffer face.")))
148 | (eval `(defface ,(nth 0 s)
149 | `((t (:background ,(nth 1 s)
150 | :foreground "#3E3D31"
151 | :inherit 'mode-line)))
152 | ,(nth 2 s)
153 | :group 'spaceline)))
154 |
155 | (defun spaceline-highlight-face-default ()
156 | "The default highlight face function.
157 | Set `spaceline-highlight-face-func' to
158 | `spaceline-highlight-face-default' to use this."
159 | 'spaceline-highlight-face)
160 |
161 | (defvar spaceline-evil-state-faces
162 | '((normal . spaceline-evil-normal)
163 | (insert . spaceline-evil-insert)
164 | (emacs . spaceline-evil-emacs)
165 | (replace . spaceline-evil-replace)
166 | (visual . spaceline-evil-visual)
167 | (motion . spaceline-evil-motion))
168 | "Association list mapping evil states to their corresponding highlight faces.
169 | Is used by `spaceline-highlight-face-evil-state'.")
170 |
171 | (defun spaceline-highlight-face-evil-state ()
172 | "Set the highlight face depending on the evil state.
173 | Set `spaceline-highlight-face-func' to
174 | `spaceline-highlight-face-evil-state' to use this."
175 | (if (bound-and-true-p evil-local-mode)
176 | (let* ((state (if (eq 'operator evil-state) evil-previous-state evil-state))
177 | (face (assq state spaceline-evil-state-faces)))
178 | (if face (cdr face) (spaceline-highlight-face-default)))
179 | (spaceline-highlight-face-default)))
180 |
181 | (defun spaceline-highlight-face-modified ()
182 | "Set the highlight face depending on the buffer modified status.
183 | Set `spaceline-highlight-face-func' to
184 | `spaceline-highlight-face-modified' to use this."
185 | (cond
186 | (buffer-read-only 'spaceline-read-only)
187 | ((buffer-modified-p) 'spaceline-modified)
188 | (t 'spaceline-unmodified)))
189 |
190 | (defun spaceline--imagep (object)
191 | "Test whether the given OBJECT is an image.
192 | An image is a list whose first element is the symbol `image'."
193 | (and (listp object)
194 | object
195 | (eq 'image (car object))))
196 |
197 | (defun spaceline--intersperse (separator seq)
198 | "Intersperses SEPARATOR between each element of SEQ.
199 | This function does not run in-place. It returns a new list."
200 | (cond
201 | ((not seq) nil)
202 | ((not (cdr seq)) seq)
203 | (t (append (list (car seq) separator)
204 | (spaceline--intersperse separator (cdr seq))))))
205 |
206 | (defun spaceline--mode-line-nonempty (seg)
207 | "Check whether a modeline segment SEG is nonempty."
208 | (let ((val (format-mode-line seg)))
209 | (cond ((listp val) val)
210 | ((stringp val) (< 0 (length val)))
211 | (t))))
212 |
213 | (defmacro spaceline--parse-segment-spec (spec &rest body)
214 | "Destructure the segment specification SPEC and then run BODY.
215 | The following bindings are available in BODY:
216 | - `segment': The segment itself, either a symbol or a literal
217 | value, or a list of such.
218 | - `sym': The function that evaluates `segment', if it is a symbol.
219 | - `sym-form': The form that evaluates the segment, if it is a
220 | symbol.
221 | - `input-props': The property list part of SPEC, if present.
222 | - `props': The full property list (including those bound to the
223 | symbol, if applicable)."
224 | (declare (indent 1))
225 | `(let* ((input (if (and (listp ,spec)
226 | (cdr ,spec)
227 | (keywordp (cadr ,spec)))
228 | ,spec
229 | (cons ,spec nil)))
230 | (segment (car input))
231 | (sym (when (symbolp segment) (intern (format "spaceline-%s-p" segment))))
232 | (sym-form (when (symbolp segment) (get sym :code)))
233 | (input-props (cdr input))
234 | (props (append input-props
235 | (when (symbolp segment) (symbol-plist sym)))))
236 | ,@body))
237 |
238 | (defun spaceline--gen-separator (face side)
239 | "Generate the code for producing a separator, if needed.
240 | Generates a separator with faces SEPARATOR-FACE (should be bound
241 | where the code runs) and FACE. SIDE is l or r."
242 | `((when needs-separator
243 | ,(if (eq 'l side)
244 | `(push (funcall default-sep separator-face ,face) result)
245 | `(push (funcall default-sep ,face separator-face) result))
246 | (cl-rotatef default-sep other-sep)
247 | (setq needs-separator nil))))
248 |
249 | (defun spaceline--gen-produce (face side)
250 | "Generate pre-production code.
251 | This code must run immediately before any segment produces
252 | output, if and only if it actually produces output. This will
253 | 1. Generate a separator with the correct FACE and SIDE.
254 | (see `spaceline--gen-separator')
255 | 2. Output the value of PRIOR, if given.
256 | 3. Reset the value of PRIOR to NEXT-PRIOR.
257 | 4. Set SEPARATOR-FACE for the next separator."
258 | `(,@(spaceline--gen-separator face side)
259 | (when prior
260 | (push prior result))
261 | (setq prior next-prior)
262 | (setq separator-face ,face)))
263 |
264 | (defun spaceline--gen-segment (segment-spec side hidden &optional outer-props deep-or-fallback deep)
265 | "Generate the code for evaluating a segment.
266 | SEGMENT-SPEC is a valid Spaceline segment. See
267 | `spaceline-compile'. SIDE is either l or r. HIDDEN is a form
268 | that evaluates to true if the segment should be hidden, nil
269 | otherwise. OUTER-PROPS is a property list with properties
270 | inherited from parent segments.
271 |
272 | DEEP-OR-FALLBACK is nil if this segment is a top level segment or
273 | a fallback for a top level segment.
274 |
275 | DEEP is nil if and only if this segment is a top level segment.
276 |
277 | This function should only be called from outside code with
278 | OUTER-PROPS, DEEP-OR-FALLBACK and DEEP set to nil.
279 |
280 | Returns a list of forms."
281 | (spaceline--parse-segment-spec segment-spec
282 | (let* (;; Assemble the properties in the correct order
283 | (props (append props outer-props))
284 |
285 | ;; Explicitly set the fallback property for child segments to nil,
286 | ;; as it should not be inherited
287 | (fallback (plist-get props :fallback))
288 | (nest-props (append '(:fallback nil) input-props outer-props))
289 |
290 | (condition (if (plist-member props :when)
291 | (plist-get props :when) t))
292 | (face (or (plist-get props :face) 'default-face))
293 | (face (if (memq face '(default-face other-face highlight-face line-face))
294 | face `(,@face)))
295 | (separator `(powerline-raw ,(or (plist-get props :separator) " ") ,face))
296 | (tight-left (or (plist-get props :tight)
297 | (plist-get props :tight-left)))
298 | (tight-right (or (plist-get props :tight)
299 | (plist-get props :tight-right)))
300 |
301 | ;; A temporary variable to check whether this segment has produced
302 | ;; output. It is uninterned to prevent it from clashing with those
303 | ;; of children or parent segments.
304 | (previous-result (make-symbol "spaceline--previous-result"))
305 |
306 | ;; A temporary variable to store the setting of `needs-separator',
307 | ;; in case we update it and need to change it back
308 | (previous-needs-separator (make-symbol "spaceline--previous-needs-separator"))
309 |
310 | ;; A temporary variable to store the setting of `separator-face',
311 | ;; in case we update it and need to change it back
312 | (previous-separator-face (make-symbol "spaceline--previous-separator-face"))
313 |
314 | clean-up-make
315 | clean-up-code)
316 |
317 | ;; On the right we output we produce output in the reverse direction,
318 | ;; so the meanings of left and right are interchanged
319 | (when (eq 'r side) (cl-rotatef tight-left tight-right))
320 |
321 | ;; Clean-up-make and clean-up-code runs for top level segments that produce output
322 | ;; Anything that modifies `result' goes in clean-up-make
323 | (setq clean-up-make
324 | ;; Add padding unless the segment is tight
325 | (unless tight-right `((push (propertize " " 'face ,face) result))))
326 | (setq clean-up-code
327 | `(;; Rotate the faces for the next top level segment
328 | ,@(unless (plist-get props :skip-alternate)
329 | '((cl-rotatef default-face other-face)))
330 | ;; We need a new separator at the next producing segment
331 | (setq needs-separator ,(not tight-right))))
332 |
333 | `(;; Store the current result pointer in the temp variable
334 | (let ((,previous-result result)
335 | (,previous-needs-separator needs-separator)
336 | (,previous-separator-face separator-face))
337 |
338 | ;; Don't produce a separator if the segment is tight
339 | ,@(when tight-left `((setq needs-separator nil)))
340 |
341 | ;; Top-level non-tight segments need padding
342 | ,@(unless (or deep-or-fallback tight-left)
343 | `((setq prior (propertize " " 'face ,face))))
344 |
345 | ;; Evaluate the segment
346 | (when ,condition
347 | ,@(cond
348 | ((listp segment)
349 | ;; List segments can potentially have a new separator between
350 | ;; their elements, but not before the first one; therefore we
351 | ;; set NEXT-PRIOR but leave PRIOR alone
352 | `((let ((next-prior ,separator))
353 | ,@(apply 'append
354 | (mapcar (lambda (s)
355 | (spaceline--gen-segment s side hidden nest-props 'deep-or-fallback 'deep))
356 | (if (eq 'r side) (reverse segment) segment))))
357 | ;; Since PRIOR may have been disrupted, we reset it here
358 | (setq prior next-prior)))
359 | ((symbolp segment)
360 | `((-when-let (value ,sym-form)
361 | ;; Symbol segments are assumed to not produce output unless
362 | ;; they evaluate to nil or an empty string
363 | (unless (and (stringp value) (string= "" value))
364 | ,@(spaceline--gen-produce face side))
365 | (cond
366 | ;; Images are lists, so they must be treated first
367 | ((spaceline--imagep value) (push value result))
368 | ((listp value)
369 | (dolist (r ,(if (eq 'l side)
370 | `(spaceline--intersperse ,separator value)
371 | `(reverse (spaceline--intersperse ,separator value))))
372 | (push (if (spaceline--imagep r) r (powerline-raw r ,face)) result)))
373 | ((and (stringp value) (string= "" value)))
374 | (t (push (powerline-raw value ,face) result))))))
375 | (t
376 | ;; Literal segments are assumed to always produce; no check for
377 | ;; empty string here
378 | `(,@(spaceline--gen-produce face side)
379 | (push (powerline-raw (format "%s" ,segment) ,face) result)))))
380 |
381 | ;; If the segment failed to produce, but has a fallback, we call the fallback
382 | ,@(when fallback
383 | `((when (eq ,previous-result result)
384 | ,@(spaceline--gen-segment fallback side hidden nest-props deep-or-fallback 'deep))))
385 |
386 | ;; Compute the length of the segment, and possibly run clean-up code
387 | ,@(unless deep
388 | `((if (eq ,previous-result result)
389 | ;; The segment didn't produce, so just set it to zero
390 | (setq segment-length 0)
391 | ;; The segment produced. First, do any clean-up that might alter the length
392 | ,@clean-up-make
393 | ;; Compute the length
394 | (let ((len (string-width (format-mode-line (powerline-render result)))))
395 | (setq segment-length (- len result-length))
396 | ;; If the segment is hidden, forcibly reset the result pointer
397 | ;; If it's not hidden, update the result length and perform the rest of the cleanup
398 | (if ,hidden
399 | (setq result ,previous-result
400 | needs-separator ,previous-needs-separator
401 | separator-face ,previous-separator-face)
402 | ,@clean-up-code
403 | (setq result-length len)))))))))))
404 |
405 | (defun spaceline-compile (&rest args)
406 | "Compile a modeline.
407 |
408 | This function accepts a number of calling conventions:
409 | - With three arguments, TARGET, LEFT and RIGHT, it compiles a
410 | modeline named TARGET, with segment lists LEFT and RIGHT for
411 | the left and right sides respectively.
412 | - With two arguments, LEFT and RIGHT, the target takes the
413 | default value `main'.
414 | - With one argument, TARGET, it recompiles the modeline named
415 | TARGET with the same segments as it was originally compiled.
416 | - With no arguments, it recompiles all existing modelines with
417 | the same segments as they were originally compiled.
418 |
419 | In all cases, a function called `spaceline-ml-TARGET' is defined,
420 | which evaluates the modeline. It can then be used as a modeline
421 | by setting `mode-line-format' to
422 |
423 | (\"%e\" (:eval (spaceline-ml-TARGET)))
424 |
425 | If `spaceline-byte-compile' is non-nil, this function will be
426 | byte-compiled. This is recommended for regular usage as it
427 | improves performance significantly.
428 |
429 | If the segments are known statically at compile time, consider
430 | using `spaceline-generate' instead.
431 |
432 | Each element in LEFT and RIGHT must be a valid segment. Namely,
433 | - A literal string, integer or floating point number; or
434 | - a symbol, which has been defined with
435 | `spaceline-define-segment'; or
436 | - a list of segments; or
437 | - a list where the first element is a segment, and the rest of
438 | the list is a plist.
439 |
440 | The supported properties are
441 | - `:priority', a number representing the priority of appearance of that
442 | segment over the others, the higher the number the higher the priority.
443 | - `:when', a form that must evaluate to non-nil for the segment to
444 | show (default t)
445 | - `:face', the face with which to render the segment; may either
446 | one of the variables `default-face', `other-face' or `highlight-face'
447 | (default `default-face') or a form evaluating to a face. Thus any
448 | face symbol which is not either of the above three must be quoted.
449 | - `:separator', a string inserted between each element in a list
450 | segment (default \" \")
451 | - `:tight-left', non-nil if the segment should have no padding on
452 | the left side (default nil)
453 | - `:tight-right', non-nil if the segment should have no padding on
454 | the right side (default nil)
455 | - `:tight', non-nil if the segment should have no padding on
456 | either side (default nil)
457 | - `:fallback', another segment that will be called if no output
458 | is produced"
459 | (declare (indent defun))
460 | (interactive)
461 | (if (not args)
462 | ;; Recompile all modelines
463 | (dolist (target spaceline--mode-lines)
464 | (spaceline-compile (car target)))
465 | (let* (;; Handle the different calling conventions
466 | (nargs (length args))
467 | (target (if (cl-oddp nargs) (pop args) 'main))
468 | (left-segs (if (> nargs 1) (pop args)
469 | (cadr (assq target spaceline--mode-lines))))
470 | (right-segs (if (> nargs 1) (pop args)
471 | (cddr (assq target spaceline--mode-lines))))
472 | (target-func (intern (format "spaceline-ml-%s" target))))
473 |
474 | (eval (macroexpand-all `(spaceline-generate ,target ,left-segs ,right-segs)))
475 |
476 | (when spaceline-byte-compile
477 | (let ((byte-compile-warnings nil))
478 | (byte-compile target-func)))
479 |
480 | ;; This is not strictly required, but it lets people use
481 | ;; `spaceline-compile' as an all-in-one fix-everything button
482 | (powerline-reset))))
483 |
484 | (defalias 'spaceline-install 'spaceline-compile)
485 |
486 | (make-obsolete-variable 'spaceline-install 'spaceline-compile "2.0.2")
487 |
488 | (defmacro spaceline-generate (&rest args)
489 | "Compile a modeline.
490 |
491 | This is a macro-version of `spaceline-compile', useful for
492 | generating a modeline function when the segments are known
493 | statically at compile time.
494 |
495 | This macro accepts two calling conventions:
496 | - With three arguments, TARGET, LEFT and RIGHT, it compiles a
497 | modeline named TARGET, with segment lists LEFT and RIGHT for
498 | the left and right sides respectively.
499 | - With two arguments, LEFT and RIGHT, the target takes the
500 | default value `main'.
501 |
502 | In all cases, a function called `spaceline-ml-TARGET' is defined,
503 | which evaluates the modeline. It can then be used as a modeline
504 | by setting `mode-line-format' to
505 |
506 | (\"%e\" (:eval (spaceline-ml-TARGET)))
507 |
508 | See the documentation for `spaceline-compile' for how to specify
509 | LEFT and RIGHT."
510 | (declare (indent defun))
511 | (let* (;; Handle the different calling conventions
512 | (nargs (length args))
513 | (target (if (cl-oddp nargs) (pop args) 'main))
514 | (left-segs (car args))
515 | (right-segs (cadr args))
516 | (target-func (intern (format "spaceline-ml-%s" target)))
517 | ;; Special support for the global segment: compile list of excludes
518 | (global-excludes (append (spaceline--global-excludes left-segs)
519 | (spaceline--global-excludes right-segs)))
520 | ;; Symbols for runtime data
521 | (left-symbol (intern (format "spaceline--segments-code-%s-left" target)))
522 | (right-symbol (intern (format "spaceline--segments-code-%s-right" target)))
523 | (priority-symbol (intern (format "spaceline--runtime-data-%s" target)))
524 | (left-code `(spaceline--code-for-side
525 | ,global-excludes ,left-symbol ,left-segs l))
526 | (right-code `(spaceline--code-for-side
527 | ,global-excludes ,right-symbol ,right-segs r)))
528 | `(progn
529 |
530 | ;; Declare global runtime defaults
531 | (spaceline--declare-runtime ,left-segs ,right-segs ,left-symbol ,right-symbol ,priority-symbol)
532 |
533 | ;; Update stored segments so that recompilation will work
534 | (unless (assq ',target spaceline--mode-lines)
535 | (push '(,target) spaceline--mode-lines))
536 | (setcdr (assq ',target spaceline--mode-lines)
537 | '(,left-segs . ,right-segs))
538 |
539 | ;; Define the function that Emacs will call to generate the mode-line's
540 | ;; format string every time the mode-line is refreshed.
541 | (defun ,target-func ()
542 | ;; Initialize the local runtime if necessary
543 | (unless ,priority-symbol
544 | (spaceline--init-runtime ,left-symbol ,right-symbol ,priority-symbol))
545 | ;; Render the modeline
546 | (let ((fmt (spaceline--render-mode-line ,left-code ,right-code)))
547 | (and spaceline-responsive
548 | (spaceline--adjust-to-window ,priority-symbol fmt)
549 | (setq fmt (spaceline--render-mode-line ,left-code ,right-code)))
550 | fmt)))))
551 |
552 | (defmacro spaceline--code-for-side
553 | (global-excludes runtime-symbol segments side)
554 | "Generate the code that will evaluate all segments for one side.
555 |
556 | GLOBAL-EXCLUDES is used for the global segment, see `spaceline-define-segment'.
557 |
558 | RUNTIME-SYMBOL is a symbol storing the runtime data for this side, one
559 | three-element vector for each top-level segment, see
560 | `spaceline--declare-runtime' and `spaceline--init-runtime'.
561 |
562 | SEGMENTS is a list of segment specifications (see `spaceline--compile') and SIDE
563 | is either l or r, respectively for the left and the right side."
564 | (let ((sep-style (format "powerline-%s" powerline-default-separator))
565 | (sep-dirs (spaceline--get-separator-dirs side)))
566 | `(let* ((default-face face1)
567 | (other-face face2)
568 | (default-sep ',(intern (format "%s-%s" sep-style (car sep-dirs))))
569 | (other-sep ',(intern (format "%s-%s" sep-style (cdr sep-dirs))))
570 | (global-excludes ',global-excludes)
571 | (result-length 0)
572 | (segment-length 0)
573 | (runtime-pointer ,runtime-symbol)
574 | prior
575 | next-prior
576 | needs-separator
577 | separator-face
578 | result)
579 | ,@(--map `(let ((runtime-data (pop runtime-pointer)))
580 | ,@(spaceline--gen-segment it side '(not (spaceline--shown runtime-data)))
581 | (spaceline--set-length runtime-data segment-length))
582 | (if (eq 'l side) segments (reverse segments)))
583 | ,@(spaceline--gen-separator 'line-face side)
584 | ,(if (eq side 'l) '(reverse result) 'result))))
585 |
586 | (defmacro spaceline--priority (val) `(aref ,val 0))
587 | (defmacro spaceline--length (val) `(aref ,val 1))
588 | (defmacro spaceline--shown (val) `(aref ,val 2))
589 | (defmacro spaceline--set-length (vec val) `(aset ,vec 1 ,val))
590 | (defmacro spaceline--set-shown (vec val) `(aset ,vec 2 ,val))
591 |
592 | (defmacro spaceline--declare-runtime
593 | (segments-left segments-right left-symbol right-symbol priority-symbol)
594 | "Initialize the global runtime data for a modeline.
595 |
596 | The runtime consist of a three-element vector for each top-level
597 | segment in the modeline. The elements are:
598 | - priority: The priority of the segment (derived from its `:priority' property)
599 | - length: The rendered length of the segment
600 | - shown: Whether the segment is displayed or not
601 |
602 | The effect of this function is to create the default values for
603 | these vectors, and store them in the varibles LEFT-SYMBOL and
604 | RIGHT-SYMBOL, respectively, which are lists. The variable
605 | PRIORITY-SYMBOL is initialized with default value nil.
606 |
607 | See `spaceline--init-runtime' for more information."
608 | (let ((left (--map (spaceline--parse-segment-spec it
609 | (vector (or (plist-get props :priority) 0) 0 t))
610 | segments-left))
611 | (right (--map (spaceline--parse-segment-spec it
612 | (vector (or (plist-get props :priority) 0) 0 t))
613 | segments-right)))
614 | `(progn
615 | ;; We use both defvar and setq so that recompilation will work.
616 | (defvar-local ,left-symbol nil "See `spaceline--declare-runtime'.")
617 | (setq-default ,left-symbol ',left)
618 | (defvar-local ,right-symbol nil "See `spaceline--declare-runtime'.")
619 | (setq-default ,right-symbol ',(reverse right))
620 | (defvar-local ,priority-symbol nil "See `spaceline--declare-runtime'.")
621 |
622 | ;; Since we have possibly changed the defaults of these variables, kill
623 | ;; any local bindings that may exist.
624 | (dolist (buf (buffer-list))
625 | (with-current-buffer buf
626 | (kill-local-variable ',left-symbol)
627 | (kill-local-variable ',right-symbol)
628 | (kill-local-variable ',priority-symbol))))))
629 |
630 | (defmacro spaceline--render-mode-line (left-code right-code)
631 | "Call powerline to generate the mode-line format string.
632 | LEFT-CODE and RIGHT-CODE are the code that will be used "
633 | `(progn
634 | (run-hooks 'spaceline-pre-hook)
635 | (let* ((active-strict (powerline-selected-window-active))
636 | (active (or spaceline-always-show-segments active-strict))
637 | (line-face (spaceline--get-face 'line active-strict))
638 | (highlight-face (spaceline--get-face 'highlight active-strict))
639 | (face1 (spaceline--get-face 'face1 active-strict))
640 | (face2 (spaceline--get-face 'face2 active-strict))
641 | (lhs ,left-code)
642 | (rhs ,right-code))
643 | (concat
644 | ,@(when spaceline-inflation
645 | `((propertize "\u200b" 'display
646 | '((raise ,(/ (1- spaceline-inflation) -2.0))
647 | (height ,spaceline-inflation)))))
648 | (powerline-render lhs)
649 | (powerline-fill line-face (powerline-width rhs))
650 | (powerline-render rhs)))))
651 |
652 | (defmacro spaceline--init-runtime (left-symbol right-symbol priority-symbol)
653 | "Initialize data structures used for the responsiveness of the modeline.
654 |
655 | This function
656 | - creates local deep copies of the global values of LEFT-SYMBOL and
657 | RIGHT-SYMBOL,
658 | - initializes PRIORITY-SYMBOl, a reordering of the same vectors whose order
659 | (by priority) decides the order of segments disappearance / reappearance with
660 | the size of the window.
661 |
662 | Note that the changes in the resulting PRIORITY-SYMBOL list are
663 | visible from LEFT-SYMBOL and RIGHT-SYMBOL, and vice versa. This
664 | creates a data structure that is efficiently accessible both in
665 | order of priority and order of segments."
666 | `(let ((left (--map (copy-tree it) (default-value ',left-symbol)))
667 | (right (--map (copy-tree it) (default-value ',right-symbol)))
668 | priority)
669 | (set (make-local-variable ',left-symbol) left)
670 | (set (make-local-variable ',right-symbol) right)
671 | (while (or left right)
672 | (when left (push (pop left) priority))
673 | (when right (push (pop right) priority)))
674 | (set (make-local-variable ',priority-symbol)
675 | (sort priority 'spaceline--compare-priorities))))
676 |
677 | (defmacro spaceline--adjust-to-window (responsiveness-runtime-data format)
678 | "Adjust the spaceline to the window by hiding or showing segments.
679 |
680 | RESPONSIVENESS-RUNTIME-DATA is a list of segments runtime data used to hide or
681 | show segments, see `spaceline--declare-runtime' for more info about
682 | how responsiveness works.
683 |
684 | FMT is the rendered modeline with the current visibility settings.
685 |
686 | Returns a truthy value if the visibility of any segment changed."
687 | ;; `1-' to not count the space generated by `powerline-fill'
688 | `(let ((total-length (1- (string-width (format-mode-line ,format))))
689 | (width (+ (window-width)
690 | (or (cdr (window-margins)) 0)
691 | (or (car (window-margins)) 0)))
692 | changed)
693 | (if (> total-length width)
694 | ;; The modeline is too long, so try to hide some segments that are shown
695 | (let ((to-hide (--drop-while (not (spaceline--shown it))
696 | ,responsiveness-runtime-data)))
697 | (--each-while to-hide
698 | (< width total-length)
699 | (cl-decf total-length (spaceline--length it))
700 | (spaceline--set-shown it nil)
701 | (setq changed t)))
702 | ;; The modeline is shorter than it could be, so try to show some hidden segments
703 | (let ((to-show (--drop-while (spaceline--shown it)
704 | (reverse ,responsiveness-runtime-data))))
705 | (--each-while to-show
706 | (> width (+ total-length (spaceline--length it)))
707 | (cl-incf total-length (spaceline--length it))
708 | (spaceline--set-shown it t)
709 | (setq changed t))))
710 | changed))
711 |
712 | (defun spaceline--compare-priorities (first-alist second-alist)
713 | "Comparison predicate for sorting the segments runtime data by priority.
714 | Used as a predicate for `sort' in `spaceline--init-runtime'."
715 | (let ((first (spaceline--priority first-alist))
716 | (second (spaceline--priority second-alist)))
717 | (< first second)))
718 |
719 | (defmacro spaceline-define-segment (name value &rest props)
720 | "Define a modeline segment called NAME with value VALUE and properties PROPS.
721 |
722 | Its value is computed by the form VALUE. The segment will not
723 | produce output if VALUE evaluates to nil or an empty string. All
724 | other values are assumed truthy.
725 |
726 | This macro defines a variable `spaceline--NAME-p' whose value can
727 | be used to switch the segment on or off. Its initial value is
728 | given by the optional keyword argument `:enabled', which defaults
729 | to true.
730 |
731 | If the segment is intended as a replacement for data which is
732 | otherwise inserted into `global-mode-string' (typically by
733 | another package), you can use the keyword argument
734 | `:global-override' to disable that. Its value is a single element
735 | or a list of elements which will be removed from
736 | `global-mode-string' before evaluation of the `global' segment.
737 | For modelines that do not use the `global' segment, this has no
738 | effect.
739 |
740 | All properties accepted in `spaceline-compile' are also accepted
741 | here. They are stored in a plist attached to the symbol
742 | `spaceline--NAME-p' to be inspected at compilation time by
743 | `spaceline-compile'.
744 |
745 | When a segment is redefined, the modelines must be recompiled for
746 | the changes to take effect."
747 | (declare (indent 1)
748 | (doc-string 2))
749 | (let* ((wrapper-func (intern (format "spaceline--segment-%S" name)))
750 | (toggle-var (intern (format "spaceline-%S-p" name)))
751 | (toggle-func (intern (format "spaceline-toggle-%S" name)))
752 | (toggle-func-on (intern (format "spaceline-toggle-%S-on" name)))
753 | (toggle-func-off (intern (format "spaceline-toggle-%S-off" name)))
754 | (docstring (when (stringp value)
755 | (prog1 value
756 | (setq value (car props)
757 | props (cdr props)))))
758 | (value `(when ,toggle-var ,value))
759 | (enabled (if (plist-member props :enabled)
760 | (plist-get props :enabled)
761 | t))
762 | (global-override (plist-get props :global-override))
763 | (global-override (if (listp global-override)
764 | global-override
765 | (list global-override))))
766 | `(progn
767 | (defvar ,toggle-var ,enabled
768 | ,(format "True if modeline segment %S is enabled." name))
769 |
770 | (defun ,toggle-func () (interactive) (setq ,toggle-var (not ,toggle-var)))
771 | (defun ,toggle-func-on () (interactive) (setq ,toggle-var t))
772 | (defun ,toggle-func-off () (interactive) (setq ,toggle-var nil))
773 |
774 | ;; Explicitly set the plist, in case the segment is redefined
775 | (let ((doc (get ',toggle-var 'variable-documentation)))
776 | (setplist ',toggle-var ',props)
777 | (put ',toggle-var 'variable-documentation doc))
778 |
779 | ;; These properties must be explicitly set
780 | (put ',toggle-var :code ',value)
781 | (put ',toggle-var :global-override ',global-override))))
782 |
783 | (defun spaceline--global-excludes (segments)
784 | "Compute global overrides from the segment list SEGMENTS."
785 | (let (excludes)
786 | (dolist (s-spec segments)
787 | (spaceline--parse-segment-spec s-spec
788 | (setq excludes (append (plist-get props :global-override) excludes))
789 | (when (listp segment)
790 | (setq excludes (append (spaceline--global-excludes segment) excludes)))))
791 | excludes))
792 |
793 | (spaceline-define-segment global
794 | (let ((global (if (listp global-mode-string)
795 | (cons "" (-difference global-mode-string global-excludes))
796 | global-mode-string)))
797 | (when (spaceline--mode-line-nonempty global)
798 | (string-trim (powerline-raw global)))))
799 |
800 | (defun spaceline--string-trim-from-center (str len)
801 | "Return STR with its center chars trimmed for it to be a maximum length of LEN.
802 | When characters are trimmed, they are replaced with '...'."
803 | (if (> (length str) len)
804 | (let ((mid (/ (- len 3) 2)))
805 | (concat (substring str 0 mid)
806 | (apply #'propertize "..." (text-properties-at (- mid 1) str))
807 | (substring str (- (1+ mid)) nil)))
808 | str))
809 |
810 | (provide 'spaceline)
811 |
812 | ;;; spaceline.el ends here
813 |
--------------------------------------------------------------------------------
/tests.el:
--------------------------------------------------------------------------------
1 | (ert-deftest spaceline-literal-segments-l ()
2 | "Tests literal segments (left side)."
3 | (let ((powerline-default-separator 'utf-8)
4 | (powerline-utf-8-separator-left ?>))
5 | (spaceline-install '("a" "b" 1.23 nil "longer" -2) nil)
6 | (should (string= " a > b > 1.23 > longer > -2 > "
7 | (spaceline-ml-main)))))
8 |
9 | (ert-deftest spaceline-list-segments-l ()
10 | "Tests list segments (left side)."
11 | (let ((powerline-default-separator 'utf-8)
12 | (powerline-utf-8-separator-left ?>))
13 | (spaceline-install '(("a" "b" "c") ("def" "ghj")) nil)
14 | (should (string= " a b c > def ghj > "
15 | (spaceline-ml-main)))))
16 |
17 | (ert-deftest spaceline-nested-list-segments-l ()
18 | "Tests nested list segments (left side)."
19 | (let ((powerline-default-separator 'utf-8)
20 | (powerline-utf-8-separator-left ?>))
21 | (spaceline-install '(("a" "b" "c") ("def" ("rofl" "mao" "sup") "ghj")) nil)
22 | (should (string= " a b c > def rofl mao sup ghj > "
23 | (spaceline-ml-main)))))
24 |
25 | (ert-deftest spaceline-symbol-l ()
26 | "Tests symbols (left side)."
27 | (let ((powerline-default-separator 'utf-8)
28 | (powerline-utf-8-separator-left ?>))
29 | (spaceline-define-segment a "" "a")
30 | (spaceline-define-segment b "" nil)
31 | (spaceline-define-segment c "" var)
32 | (spaceline-install '(a b) nil)
33 | (should (string= " a > " (spaceline-ml-main)))
34 | (spaceline-install '(a b c) nil)
35 | (let ((var "alpha"))
36 | (should (string= " a > alpha > " (spaceline-ml-main))))
37 | (let ((var "beta"))
38 | (should (string= " a > beta > " (spaceline-ml-main))))))
39 |
40 | (ert-deftest spaceline-list-separators-l ()
41 | "Tests the :separator property of lists (left side)."
42 | (let ((powerline-default-separator 'utf-8)
43 | (powerline-utf-8-separator-left ?>))
44 | (spaceline-install '((("a" "b" "c") :separator "~~")) nil)
45 | (should (string= " a~~b~~c > " (spaceline-ml-main)))))
46 |
47 | (ert-deftest spaceline-nested-list-separators-l ()
48 | "Tests the :separator property of nested lists (left side)."
49 | (let ((powerline-default-separator 'utf-8)
50 | (powerline-utf-8-separator-left ?>))
51 | (spaceline-install '((("a" (("b" "c" "d") :separator "$$") "e") :separator "~~")) nil)
52 | (should (string= " a~~b$$c$$d~~e > " (spaceline-ml-main)))))
53 |
54 | (ert-deftest spaceline-symbol-list-l ()
55 | "Tests symbols returning lists, with the :separator property (left side)."
56 | (let ((powerline-default-separator 'utf-8)
57 | (powerline-utf-8-separator-left ?>))
58 | (spaceline-define-segment a "" '("a" "b" "c"))
59 | (spaceline-define-segment b "" '("a" "b" "c") :separator "^")
60 | (spaceline-install '(a) nil)
61 | (should (string= " a b c > " (spaceline-ml-main)))
62 | (spaceline-install '((a :separator ".")) nil)
63 | (should (string= " a.b.c > " (spaceline-ml-main)))
64 | (spaceline-install '(b) nil)
65 | (should (string= " a^b^c > " (spaceline-ml-main)))
66 | (spaceline-install '((b :separator "!")) nil)
67 | (should (string= " a!b!c > " (spaceline-ml-main)))))
68 |
69 | (ert-deftest spaceline-fallback-literal-l ()
70 | "Tests the :fallback property for literals (left side)."
71 | (let ((powerline-default-separator 'utf-8)
72 | (powerline-utf-8-separator-left ?>))
73 | (spaceline-install '((nil :fallback "b")) nil)
74 | (should (string= " b > " (spaceline-ml-main)))
75 | (spaceline-install '(("a" :fallback "b")) nil)
76 | (should (string= " a > " (spaceline-ml-main)))))
77 |
78 | (ert-deftest spaceline-fallback-symbol-l ()
79 | "Tests the :fallback property for symbols (left side)."
80 | (spaceline-define-segment success "" "success")
81 | (spaceline-define-segment failure "" nil)
82 | (spaceline-define-segment fallback "" nil :fallback success)
83 | (let ((powerline-default-separator 'utf-8)
84 | (powerline-utf-8-separator-left ?>))
85 | (spaceline-install '((failure :fallback "b")) nil)
86 | (should (string= " b > " (spaceline-ml-main)))
87 | (spaceline-install '((success :fallback "b")) nil)
88 | (should (string= " success > " (spaceline-ml-main)))
89 | (spaceline-install '(fallback) nil)
90 | (should (string= " success > " (spaceline-ml-main)))))
91 |
92 | (ert-deftest spaceline-tight-l ()
93 | "Tests the :tight properties (left side)."
94 | (let ((powerline-default-separator 'utf-8)
95 | (powerline-utf-8-separator-left ?>))
96 | (spaceline-install '("a" ("b" :tight t) "c") nil)
97 | (should (string= " a b c > " (spaceline-ml-main)))
98 | (spaceline-install '("a" ("b" :tight-left t) "c") nil)
99 | (should (string= " a b > c > " (spaceline-ml-main)))
100 | (spaceline-install '("a" ("b" :tight-right t) "c") nil)
101 | (should (string= " a > b c > " (spaceline-ml-main)))
102 | (spaceline-define-segment tight "" "tight" :tight t)
103 | (spaceline-install '("a" tight "c") nil)
104 | (should (string= " a tight c > " (spaceline-ml-main)))))
105 |
106 | (ert-deftest spaceline-literal-segments-r ()
107 | "Tests literal segments (right side)."
108 | (let ((powerline-default-separator 'utf-8)
109 | (powerline-utf-8-separator-right ?<))
110 | (spaceline-install nil '("a" "b" 1.23 nil "longer" -2))
111 | (should (string= " < a < b < 1.23 < longer < -2 "
112 | (spaceline-ml-main)))))
113 |
114 | (ert-deftest spaceline-list-segments-r ()
115 | "Tests list segments (right side)."
116 | (let ((powerline-default-separator 'utf-8)
117 | (powerline-utf-8-separator-right ?<))
118 | (spaceline-install nil '(("a" "b" "c") ("def" "ghj")))
119 | (should (string= " < a b c < def ghj "
120 | (spaceline-ml-main)))))
121 |
122 | (ert-deftest spaceline-nested-list-segments-r ()
123 | "Tests nested list segments (right side)."
124 | (let ((powerline-default-separator 'utf-8)
125 | (powerline-utf-8-separator-right ?<))
126 | (spaceline-install nil '(("a" "b" "c") ("def" ("rofl" "mao" "sup") "ghj")))
127 | (should (string= " < a b c < def rofl mao sup ghj "
128 | (spaceline-ml-main)))))
129 |
130 | (ert-deftest spaceline-symbol-r ()
131 | "Tests symbols (right side)."
132 | (let ((powerline-default-separator 'utf-8)
133 | (powerline-utf-8-separator-right ?<))
134 | (spaceline-define-segment a "" "a")
135 | (spaceline-define-segment b "" nil)
136 | (spaceline-define-segment c "" var)
137 | (spaceline-install nil '(a b))
138 | (should (string= " < a " (spaceline-ml-main)))
139 | (spaceline-install nil '(a b c))
140 | (let ((var "alpha"))
141 | (should (string= " < a < alpha " (spaceline-ml-main))))
142 | (let ((var "beta"))
143 | (should (string= " < a < beta " (spaceline-ml-main))))))
144 |
145 | (ert-deftest spaceline-list-separators-r ()
146 | "Tests the :separator property of lists (right side)."
147 | (let ((powerline-default-separator 'utf-8)
148 | (powerline-utf-8-separator-right ?<))
149 | (spaceline-install nil '((("a" "b" "c") :separator "~~")))
150 | (should (string= " < a~~b~~c " (spaceline-ml-main)))))
151 |
152 | (ert-deftest spaceline-nested-list-separators-r ()
153 | "Tests the :separator property of nested lists (right side)."
154 | (let ((powerline-default-separator 'utf-8)
155 | (powerline-utf-8-separator-right ?<))
156 | (spaceline-install nil '((("a" (("b" "c" "d") :separator "$$") "e") :separator "~~")))
157 | (should (string= " < a~~b$$c$$d~~e " (spaceline-ml-main)))))
158 |
159 | (ert-deftest spaceline-symbol-list-r ()
160 | "Tests symbols returning lists, with the :separator property (right side)."
161 | (let ((powerline-default-separator 'utf-8)
162 | (powerline-utf-8-separator-right ?<))
163 | (spaceline-define-segment a "" '("a" "b" "c"))
164 | (spaceline-define-segment b "" '("a" "b" "c") :separator "^")
165 | (spaceline-install nil '(a))
166 | (should (string= " < a b c " (spaceline-ml-main)))
167 | (spaceline-install nil '((a :separator ".")))
168 | (should (string= " < a.b.c " (spaceline-ml-main)))
169 | (spaceline-install nil '(b))
170 | (should (string= " < a^b^c " (spaceline-ml-main)))
171 | (spaceline-install nil '((b :separator "!")))
172 | (should (string= " < a!b!c " (spaceline-ml-main)))))
173 |
174 | (ert-deftest spaceline-fallback-literal-r ()
175 | "Tests the :fallback property for literals (right side)."
176 | (let ((powerline-default-separator 'utf-8)
177 | (powerline-utf-8-separator-right ?<))
178 | (spaceline-install nil '((nil :fallback "b")))
179 | (should (string= " < b " (spaceline-ml-main)))
180 | (spaceline-install nil '(("a" :fallback "b")))
181 | (should (string= " < a " (spaceline-ml-main)))))
182 |
183 | (ert-deftest spaceline-fallback-symbol-r ()
184 | "Tests the :fallback property for symbols (right side)."
185 | (spaceline-define-segment success "" "success")
186 | (spaceline-define-segment failure "" nil)
187 | (spaceline-define-segment fallback "" nil :fallback success)
188 | (let ((powerline-default-separator 'utf-8)
189 | (powerline-utf-8-separator-right ?<))
190 | (spaceline-install nil '((failure :fallback "b")))
191 | (should (string= " < b " (spaceline-ml-main)))
192 | (spaceline-install nil '((success :fallback "b")))
193 | (should (string= " < success " (spaceline-ml-main)))
194 | (spaceline-install nil '(fallback))
195 | (should (string= " < success " (spaceline-ml-main)))))
196 |
197 | (ert-deftest spaceline-tight-r ()
198 | "Tests the :tight properties (right side)."
199 | (let ((powerline-default-separator 'utf-8)
200 | (powerline-utf-8-separator-right ?<))
201 | (spaceline-install nil '("a" ("b" :tight t) "c"))
202 | (should (string= " < a b c " (spaceline-ml-main)))
203 | (spaceline-install nil '("a" ("b" :tight-left t) "c"))
204 | (should (string= " < a b < c " (spaceline-ml-main)))
205 | (spaceline-install nil '("a" ("b" :tight-right t) "c"))
206 | (should (string= " < a < b c " (spaceline-ml-main)))
207 | (spaceline-define-segment tight "" "tight" :tight t)
208 | (spaceline-install nil '("a" tight "c"))
209 | (should (string= " < a tight c " (spaceline-ml-main)))))
210 |
211 | (ert-deftest spaceline-recompile ()
212 | "Tests recompilation."
213 | (let ((powerline-default-separator 'utf-8)
214 | (powerline-utf-8-separator-left ?>))
215 | (spaceline-define-segment a "" "a")
216 | (spaceline-install '(a) nil)
217 | (should (string= " a > " (spaceline-ml-main)))
218 | (spaceline-define-segment a "" "b")
219 | (should (string= " a > " (spaceline-ml-main)))
220 | (spaceline-install)
221 | (should (string= " b > " (spaceline-ml-main)))
222 | (spaceline-define-segment a "" "a" :tight t)
223 | (should (string= " b > " (spaceline-ml-main)))
224 | (spaceline-install)
225 | (should (string= "a " (spaceline-ml-main)))
226 | (spaceline-define-segment a "" "c")
227 | (should (string= "a " (spaceline-ml-main)))
228 | (spaceline-install)
229 | (should (string= " c > " (spaceline-ml-main)))))
230 |
--------------------------------------------------------------------------------