| 1 | ;;; gnus-edit.el --- Gnus SCORE file editing |
| 2 | |
| 3 | ;; Copyright (C) 1995 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: Per Abrahamsen <abraham@iesd.auc.dk> |
| 6 | ;; Keywords: news, help |
| 7 | ;; Version: 0.2 |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation; either version 2, or (at your option) |
| 14 | ;; any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
| 23 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 24 | ;; Boston, MA 02111-1307, USA. |
| 25 | |
| 26 | ;;; Commentary: |
| 27 | |
| 28 | ;; Type `M-x gnus-score-customize RET' to invoke. |
| 29 | |
| 30 | ;;; Code: |
| 31 | |
| 32 | (require 'custom) |
| 33 | (require 'gnus-score) |
| 34 | |
| 35 | (defconst gnus-score-custom-data |
| 36 | '((tag . "Score") |
| 37 | (doc . "Customization of Gnus SCORE files. |
| 38 | |
| 39 | SCORE files allow you to assign a score to each article when you enter |
| 40 | a group, and automatically mark the articles as read or delete them |
| 41 | based on the score. In the summary buffer you can use the score to |
| 42 | sort the articles by score (`C-c C-s C-s') or to jump to the unread |
| 43 | article with the highest score (`,').") |
| 44 | (type . group) |
| 45 | (data "\n" |
| 46 | ((header . nil) |
| 47 | (doc . "Name of SCORE file to customize. |
| 48 | |
| 49 | Enter the name in the `File' field, then push the [Load] button to |
| 50 | load it. When done editing, push the [Save] button to save the file. |
| 51 | |
| 52 | Several score files may apply to each group, and several groups may |
| 53 | use the same score file. This is controlled implicitly by the name of |
| 54 | the score file and the value of the global variable |
| 55 | `gnus-score-find-score-files-function', and explicitly by the the |
| 56 | `Files' and `Exclude Files' entries.") |
| 57 | (compact . t) |
| 58 | (type . group) |
| 59 | (data ((tag . "Load") |
| 60 | (type . button) |
| 61 | (query . gnus-score-custom-load)) |
| 62 | ((tag . "Save") |
| 63 | (type . button) |
| 64 | (query . gnus-score-custom-save)) |
| 65 | ((name . file) |
| 66 | (tag . "File") |
| 67 | (directory . "~/News/") |
| 68 | (default-file . "SCORE") |
| 69 | (type . file)))) |
| 70 | ((name . files) |
| 71 | (tag . "Files") |
| 72 | (doc . "\ |
| 73 | List of score files to load when the the current score file is loaded. |
| 74 | You can use this to share score entries between multiple score files. |
| 75 | |
| 76 | Push the `[INS]' button add a score file to the list, or `[DEL]' to |
| 77 | delete a score file from the list.") |
| 78 | (type . list) |
| 79 | (data ((type . repeat) |
| 80 | (header . nil) |
| 81 | (data (type . file) |
| 82 | (directory . "~/News/"))))) |
| 83 | ((name . exclude-files) |
| 84 | (tag . "Exclude Files") |
| 85 | (doc . "\ |
| 86 | List of score files to exclude when the the current score file is loaded. |
| 87 | You can use this if you have a score file you want to share between a |
| 88 | number of newsgroups, except for the newsgroup this score file |
| 89 | matches. [ Did anyone get that? ] |
| 90 | |
| 91 | Push the `[INS]' button add a score file to the list, or `[DEL]' to |
| 92 | delete a score file from the list.") |
| 93 | (type . list) |
| 94 | (data ((type . repeat) |
| 95 | (header . nil) |
| 96 | (data (type . file) |
| 97 | (directory . "~/News/"))))) |
| 98 | ((name . mark) |
| 99 | (tag . "Mark") |
| 100 | (doc . "\ |
| 101 | Articles below this score will be automatically marked as read. |
| 102 | |
| 103 | This means that when you enter the summary buffer, the articles will |
| 104 | be shown but will already be marked as read. You can then press `x' |
| 105 | to get rid of them entirely. |
| 106 | |
| 107 | By default articles with a negative score will be marked as read. To |
| 108 | change this, push the `Mark' button, and choose `Integer'. You can |
| 109 | then enter a value in the `Mark' field.") |
| 110 | (type . gnus-score-custom-maybe-type)) |
| 111 | ((name . expunge) |
| 112 | (tag . "Expunge") |
| 113 | (doc . "\ |
| 114 | Articles below this score will not be shown in the summary buffer.") |
| 115 | (type . gnus-score-custom-maybe-type)) |
| 116 | ((name . mark-and-expunge) |
| 117 | (tag . "Mark and Expunge") |
| 118 | (doc . "\ |
| 119 | Articles below this score will be marked as read, but not shown. |
| 120 | |
| 121 | Someone should explain me the difference between this and `expunge' |
| 122 | alone or combined with `mark'.") |
| 123 | (type . gnus-score-custom-maybe-type)) |
| 124 | ((name . eval) |
| 125 | (tag . "Eval") |
| 126 | (doc . "\ |
| 127 | Evaluate this lisp expression when the entering summary buffer.") |
| 128 | (type . sexp)) |
| 129 | ((name . read-only) |
| 130 | (tag . "Read Only") |
| 131 | (doc . "Read-only score files will not be updated or saved. |
| 132 | Except from this buffer, of course!") |
| 133 | (type . toggle)) |
| 134 | ((type . doc) |
| 135 | (doc . "\ |
| 136 | Each news header has an associated list of score entries. |
| 137 | You can use the [INS] buttons to add new score entries anywhere in the |
| 138 | list, or the [DEL] buttons to delete specific score entries. |
| 139 | |
| 140 | Each score entry should specify a string that should be matched with |
| 141 | the content actual header in order to determine whether the entry |
| 142 | applies to that header. Enter that string in the `Match' field. |
| 143 | |
| 144 | If the score entry matches, the articles score will be adjusted with |
| 145 | some amount. Enter that amount in the in the `Score' field. You |
| 146 | should specify a positive amount for score entries that matches |
| 147 | articles you find interesting, and a negative amount for score entries |
| 148 | matching articles you would rather avoid. The final score for the |
| 149 | article will be the sum of the score of all score entries that match |
| 150 | the article. |
| 151 | |
| 152 | The score entry can be either permanent or expirable. To make the |
| 153 | entry permanent, push the `Date' button and choose the `Permanent' |
| 154 | entry. To make the entry expirable, choose instead the `Integer' |
| 155 | entry. After choosing the you can enter the date the score entry was |
| 156 | last matched in the `Date' field. The date will be automatically |
| 157 | updated each time the score entry matches an article. When the date |
| 158 | become too old, the the score entry will be removed. |
| 159 | |
| 160 | For your convenience, the date is specified as the number of days |
| 161 | elapsed since the (imaginary) Gregorian date Sunday, December 31, 1 |
| 162 | BC. |
| 163 | |
| 164 | Finally, you can choose what kind of match you want to perform by |
| 165 | pushing the `Type' button. For most entries you can choose between |
| 166 | `Exact' which mean the header content must be exactly identical to the |
| 167 | match string, or `Substring' meaning the match string should be |
| 168 | somewhere in the header content, or even `Regexp' to use Emacs regular |
| 169 | expression matching. The last choice is `Fuzzy' which is like `Exact' |
| 170 | except that whitespace derivations, a beginning `Re:' or a terminating |
| 171 | parenthetical remark are all ignored. Each of the four types have a |
| 172 | variant which will ignore case in the comparison. That variant is |
| 173 | indicated with a `(fold)' after its name.")) |
| 174 | ((name . from) |
| 175 | (tag . "From") |
| 176 | (doc . "Scoring based on the authors email address.") |
| 177 | (type . gnus-score-custom-string-type)) |
| 178 | ((name . subject) |
| 179 | (tag . "Subject") |
| 180 | (doc . "Scoring based on the articles subject.") |
| 181 | (type . gnus-score-custom-string-type)) |
| 182 | ((name . followup) |
| 183 | (tag . "Followup") |
| 184 | (doc . "Scoring based on who the article is a followup to. |
| 185 | |
| 186 | If you want to see all followups to your own articles, add an entry |
| 187 | with a positive score matching your email address here. You can also |
| 188 | put an entry with a negative score matching someone who is so annoying |
| 189 | that you don't even want to see him quoted in followups.") |
| 190 | (type . gnus-score-custom-string-type)) |
| 191 | ((name . xref) |
| 192 | (tag . "Xref") |
| 193 | (doc . "Scoring based on article crossposting. |
| 194 | |
| 195 | If you want to score based on which newsgroups an article is posted |
| 196 | to, this is the header to use. The syntax is a little different from |
| 197 | the `Newsgroups' header, but scoring in `Xref' is much faster. As an |
| 198 | example, to match all crossposted articles match on `:.*:' using the |
| 199 | `Regexp' type.") |
| 200 | (type . gnus-score-custom-string-type)) |
| 201 | ((name . references) |
| 202 | (tag . "References") |
| 203 | (doc . "Scoring based on article references. |
| 204 | |
| 205 | The `References' header gives you an alternative way to score on |
| 206 | followups. If you for example want to see follow all discussions |
| 207 | where people from `iesd.auc.dk' school participate, you can add a |
| 208 | substring match on `iesd.auc.dk>' on this header.") |
| 209 | (type . gnus-score-custom-string-type)) |
| 210 | ((name . message-id) |
| 211 | (tag . "Message-ID") |
| 212 | (doc . "Scoring based on the articles message-id. |
| 213 | |
| 214 | This isn't very useful, but Lars like completeness. You can use it to |
| 215 | match all messaged generated by recent Gnus version with a `Substring' |
| 216 | match on `.fsf@'.") |
| 217 | (type . gnus-score-custom-string-type)) |
| 218 | ((type . doc) |
| 219 | (doc . "\ |
| 220 | WARNING: Scoring on the following three pseudo headers is very slow! |
| 221 | Scoring on any of the real headers use a technique that avoids |
| 222 | scanning the entire article, only the actual headers you score on are |
| 223 | scanned, and this scanning has been heavily optimized. Using just a |
| 224 | single entry for one the three pseudo-headers `Head', `Body', and |
| 225 | `All' will require GNUS to retrieve and scan the entire article, which |
| 226 | can be very slow on large groups. However, if you add one entry for |
| 227 | any of these headers, you can just as well add several. Each |
| 228 | subsequent entry cost relatively little extra time.")) |
| 229 | ((name . head) |
| 230 | (tag . "Head") |
| 231 | (doc . "Scoring based on the article header. |
| 232 | |
| 233 | Instead of matching the content of a single header, the entire header |
| 234 | section of the article is matched. You can use this to match on |
| 235 | arbitrary headers, foe example to single out TIN lusers, use a substring |
| 236 | match on `Newsreader: TIN'. That should get 'em!") |
| 237 | (type . gnus-score-custom-string-type)) |
| 238 | ((name . body) |
| 239 | (tag . "Body") |
| 240 | (doc . "Scoring based on the article body. |
| 241 | |
| 242 | If you think any article that mentions `Kibo' is inherently |
| 243 | interesting, do a substring match on His name. You Are Allowed.") |
| 244 | (type . gnus-score-custom-string-type)) |
| 245 | ((name . all) |
| 246 | (tag . "All") |
| 247 | (doc . "Scoring based on the whole article.") |
| 248 | (type . gnus-score-custom-string-type)) |
| 249 | ((name . date) |
| 250 | (tag . "Date") |
| 251 | (doc . "Scoring based on article date. |
| 252 | |
| 253 | You can change the score of articles that have been posted before, |
| 254 | after, or at a specific date. You should add the date in the `Match' |
| 255 | field, and then select `before', `after', or `at' by pushing the |
| 256 | `Type' button. Imagine you want to lower the score of very old |
| 257 | articles, or want to raise the score of articles from the future (such |
| 258 | things happen!). Then you can't use date scoring for that. In fact, |
| 259 | I can't imagine anything you would want to use this for. |
| 260 | |
| 261 | For your convenience, the date is specified in Usenet date format.") |
| 262 | (type . gnus-score-custom-date-type)) |
| 263 | ((type . doc) |
| 264 | (doc . "\ |
| 265 | The Lines and Chars headers use integer based scoring. |
| 266 | |
| 267 | This means that you should write an integer in the `Match' field, and |
| 268 | the push the `Type' field to if the `Chars' or `Lines' header should |
| 269 | be larger, equal, or smaller than the number you wrote in the match |
| 270 | field.")) |
| 271 | ((name . chars) |
| 272 | (tag . "Characters") |
| 273 | (doc . "Scoring based on the number of characters in the article.") |
| 274 | (type . gnus-score-custom-integer-type)) |
| 275 | ((name . lines) |
| 276 | (tag . "Lines") |
| 277 | (doc . "Scoring based on the number of lines in the article.") |
| 278 | (type . gnus-score-custom-integer-type)) |
| 279 | ((name . orphan) |
| 280 | (tag . "Orphan") |
| 281 | (doc . "Score to add to articles with no parents.") |
| 282 | (type . gnus-score-custom-maybe-type)) |
| 283 | ((name . adapt) |
| 284 | (tag . "Adapt") |
| 285 | (doc . "Adapting the score files to your newsreading habits. |
| 286 | |
| 287 | When you have finished reading a group GNUS can automatically create |
| 288 | new score entries based on which articles you read and which you |
| 289 | skipped. This is normally controlled by the two global variables |
| 290 | `gnus-use-adaptive-scoring' and `gnus-default-adaptive-score-alist', |
| 291 | The first determines whether adaptive scoring should be enabled or |
| 292 | not, while the second determines what score entries should be created. |
| 293 | |
| 294 | You can overwrite the setting of `gnus-use-adaptive-scoring' by |
| 295 | selecting `Enable' or `Disable' by pressing the `Adapt' button. |
| 296 | Selecting `Custom' will allow you to specify the exact adaptation |
| 297 | rules (overwriting `gnus-default-adaptive-score-alist').") |
| 298 | (type . choice) |
| 299 | (data ((tag . "Default") |
| 300 | (default . nil) |
| 301 | (type . const)) |
| 302 | ((tag . "Enable") |
| 303 | (default . t) |
| 304 | (type . const)) |
| 305 | ((tag . "Disable") |
| 306 | (default . ignore) |
| 307 | (type . const)) |
| 308 | ((tag . "Custom") |
| 309 | (doc . "Customization of adaptive scoring. |
| 310 | |
| 311 | Each time you read an article it will be marked as read. Likewise, if |
| 312 | you delete it it will be marked as deleted, and if you tick it it will |
| 313 | be marked as ticked. When you leave a group, GNUS can automatically |
| 314 | create score file entries based on these marks, so next time you enter |
| 315 | the group articles with subjects that you read last time have higher |
| 316 | score and articles with subjects that deleted will have lower score. |
| 317 | |
| 318 | Below is a list of such marks. You can insert new marks to the list |
| 319 | by pushing on one of the `[INS]' buttons in the left margin to create |
| 320 | a new entry and then pushing the `Mark' button to select the mark. |
| 321 | For each mark there is another list, this time of article headers, |
| 322 | which determine how the mark should affect that header. The `[INS]' |
| 323 | buttons of this list are indented to indicate that the belong to the |
| 324 | mark above. Push the `Header' button to choose a header, and then |
| 325 | enter a score value in the `Score' field. |
| 326 | |
| 327 | For each article that are marked with `Mark' when you leave the |
| 328 | group, a temporary score entry for the articles `Header' with the |
| 329 | value of `Score' will be added the adapt file. If the score entry |
| 330 | already exists, `Score' will be added to its value. If you understood |
| 331 | that, you are smart. |
| 332 | |
| 333 | You can select the special value `Other' when pressing the `Mark' or |
| 334 | `Header' buttons. This is because Lars might add more useful values |
| 335 | there. If he does, it is up to you to figure out what they are named.") |
| 336 | (type . list) |
| 337 | (default . ((__uninitialized__))) |
| 338 | (data ((type . repeat) |
| 339 | (header . nil) |
| 340 | (data . ((type . list) |
| 341 | (header . nil) |
| 342 | (compact . t) |
| 343 | (data ((type . choice) |
| 344 | (tag . "Mark") |
| 345 | (data ((tag . "Unread") |
| 346 | (default . gnus-unread-mark) |
| 347 | (type . const)) |
| 348 | ((tag . "Ticked") |
| 349 | (default . gnus-ticked-mark) |
| 350 | (type . const)) |
| 351 | ((tag . "Dormant") |
| 352 | (default . gnus-dormant-mark) |
| 353 | (type . const)) |
| 354 | ((tag . "Deleted") |
| 355 | (default . gnus-del-mark) |
| 356 | (type . const)) |
| 357 | ((tag . "Read") |
| 358 | (default . gnus-read-mark) |
| 359 | (type . const)) |
| 360 | ((tag . "Expirable") |
| 361 | (default . gnus-expirable-mark) |
| 362 | (type . const)) |
| 363 | ((tag . "Killed") |
| 364 | (default . gnus-killed-mark) |
| 365 | (type . const)) |
| 366 | ((tag . "Kill-file") |
| 367 | (default . gnus-kill-file-mark) |
| 368 | (type . const)) |
| 369 | ((tag . "Low-score") |
| 370 | (default . gnus-low-score-mark) |
| 371 | (type . const)) |
| 372 | ((tag . "Catchup") |
| 373 | (default . gnus-catchup-mark) |
| 374 | (type . const)) |
| 375 | ((tag . "Ancient") |
| 376 | (default . gnus-ancient-mark) |
| 377 | (type . const)) |
| 378 | ((tag . "Canceled") |
| 379 | (default . gnus-canceled-mark) |
| 380 | (type . const)) |
| 381 | ((prompt . "Other") |
| 382 | (default . ??) |
| 383 | (type . sexp)))) |
| 384 | ((type . repeat) |
| 385 | (prefix . " ") |
| 386 | (data . ((type . list) |
| 387 | (compact . t) |
| 388 | (data ((tag . "Header") |
| 389 | (type . choice) |
| 390 | (data ((tag . "Subject") |
| 391 | (default . subject) |
| 392 | (type . const)) |
| 393 | ((prompt . "From") |
| 394 | (tag . "From ") |
| 395 | (default . from) |
| 396 | (type . const)) |
| 397 | ((prompt . "Other") |
| 398 | (width . 7) |
| 399 | (default . nil) |
| 400 | (type . symbol)))) |
| 401 | ((tag . "Score") |
| 402 | (type . integer)))))))))))))) |
| 403 | ((name . local) |
| 404 | (tag . "Local") |
| 405 | (doc . "\ |
| 406 | List of local variables to set when this score file is loaded. |
| 407 | |
| 408 | Using this entry can provide a convenient way to set variables that |
| 409 | will affect the summary mode for only some specific groups, i.e. those |
| 410 | groups matched by the current score file.") |
| 411 | (type . list) |
| 412 | (data ((type . repeat) |
| 413 | (header . nil) |
| 414 | (data . ((type . list) |
| 415 | (compact . t) |
| 416 | (data ((tag . "Name") |
| 417 | (width . 26) |
| 418 | (type . symbol)) |
| 419 | ((tag . "Value") |
| 420 | (width . 26) |
| 421 | (type . sexp))))))))))) |
| 422 | |
| 423 | (defconst gnus-score-custom-type-properties |
| 424 | '((gnus-score-custom-maybe-type |
| 425 | (type . choice) |
| 426 | (data ((type . integer) |
| 427 | (default . 0)) |
| 428 | ((tag . "Default") |
| 429 | (type . const) |
| 430 | (default . nil)))) |
| 431 | (gnus-score-custom-string-type |
| 432 | (type . list) |
| 433 | (data ((type . repeat) |
| 434 | (header . nil) |
| 435 | (data . ((type . list) |
| 436 | (compact . t) |
| 437 | (data ((tag . "Match") |
| 438 | (width . 59) |
| 439 | (type . string)) |
| 440 | "\n " |
| 441 | ((tag . "Score") |
| 442 | (type . integer)) |
| 443 | ((tag . "Date") |
| 444 | (type . choice) |
| 445 | (data ((type . integer) |
| 446 | (default . 0) |
| 447 | (width . 9)) |
| 448 | ((tag . "Permanent") |
| 449 | (type . const) |
| 450 | (default . nil)))) |
| 451 | ((tag . "Type") |
| 452 | (type . choice) |
| 453 | (data ((tag . "Exact") |
| 454 | (default . E) |
| 455 | (type . const)) |
| 456 | ((tag . "Substring") |
| 457 | (default . S) |
| 458 | (type . const)) |
| 459 | ((tag . "Regexp") |
| 460 | (default . R) |
| 461 | (type . const)) |
| 462 | ((tag . "Fuzzy") |
| 463 | (default . F) |
| 464 | (type . const)) |
| 465 | ((tag . "Exact (fold)") |
| 466 | (default . e) |
| 467 | (type . const)) |
| 468 | ((tag . "Substring (fold)") |
| 469 | (default . s) |
| 470 | (type . const)) |
| 471 | ((tag . "Regexp (fold)") |
| 472 | (default . r) |
| 473 | (type . const)) |
| 474 | ((tag . "Fuzzy (fold)") |
| 475 | (default . f) |
| 476 | (type . const)))))))))) |
| 477 | (gnus-score-custom-integer-type |
| 478 | (type . list) |
| 479 | (data ((type . repeat) |
| 480 | (header . nil) |
| 481 | (data . ((type . list) |
| 482 | (compact . t) |
| 483 | (data ((tag . "Match") |
| 484 | (type . integer)) |
| 485 | ((tag . "Score") |
| 486 | (type . integer)) |
| 487 | ((tag . "Date") |
| 488 | (type . choice) |
| 489 | (data ((type . integer) |
| 490 | (default . 0) |
| 491 | (width . 9)) |
| 492 | ((tag . "Permanent") |
| 493 | (type . const) |
| 494 | (default . nil)))) |
| 495 | ((tag . "Type") |
| 496 | (type . choice) |
| 497 | (data ((tag . "<") |
| 498 | (default . <) |
| 499 | (type . const)) |
| 500 | ((tag . ">") |
| 501 | (default . >) |
| 502 | (type . const)) |
| 503 | ((tag . "=") |
| 504 | (default . =) |
| 505 | (type . const)) |
| 506 | ((tag . ">=") |
| 507 | (default . >=) |
| 508 | (type . const)) |
| 509 | ((tag . "<=") |
| 510 | (default . <=) |
| 511 | (type . const)))))))))) |
| 512 | (gnus-score-custom-date-type |
| 513 | (type . list) |
| 514 | (data ((type . repeat) |
| 515 | (header . nil) |
| 516 | (data . ((type . list) |
| 517 | (compact . t) |
| 518 | (data ((tag . "Match") |
| 519 | (width . 59) |
| 520 | (type . string)) |
| 521 | "\n " |
| 522 | ((tag . "Score") |
| 523 | (type . integer)) |
| 524 | ((tag . "Date") |
| 525 | (type . choice) |
| 526 | (data ((type . integer) |
| 527 | (default . 0) |
| 528 | (width . 9)) |
| 529 | ((tag . "Permanent") |
| 530 | (type . const) |
| 531 | (default . nil)))) |
| 532 | ((tag . "Type") |
| 533 | (type . choice) |
| 534 | (data ((tag . "Before") |
| 535 | (default . before) |
| 536 | (type . const)) |
| 537 | ((tag . "After") |
| 538 | (default . after) |
| 539 | (type . const)) |
| 540 | ((tag . "At") |
| 541 | (default . at) |
| 542 | (type . const)))))))))))) |
| 543 | |
| 544 | (defvar gnus-score-custom-file nil |
| 545 | "Name of SCORE file being customized.") |
| 546 | |
| 547 | (defun gnus-score-customize () |
| 548 | "Create a buffer for editing gnus SCORE files." |
| 549 | (interactive) |
| 550 | (let (gnus-score-alist) |
| 551 | (custom-buffer-create "*Score Edit*" gnus-score-custom-data |
| 552 | gnus-score-custom-type-properties |
| 553 | 'gnus-score-custom-set |
| 554 | 'gnus-score-custom-get |
| 555 | 'gnus-score-custom-save)) |
| 556 | (make-local-variable 'gnus-score-custom-file) |
| 557 | (setq gnus-score-custom-file (expand-file-name "SCORE" "~/News")) |
| 558 | (make-local-variable 'gnus-score-alist) |
| 559 | (setq gnus-score-alist nil) |
| 560 | (custom-reset-all)) |
| 561 | |
| 562 | (defun gnus-score-custom-get (name) |
| 563 | (if (eq name 'file) |
| 564 | gnus-score-custom-file |
| 565 | (let ((entry (assoc (symbol-name name) gnus-score-alist))) |
| 566 | (if entry |
| 567 | (mapcar 'gnus-score-custom-sanify (cdr entry)) |
| 568 | (setq entry (assoc name gnus-score-alist)) |
| 569 | (if (or (memq name '(files exclude-files local)) |
| 570 | (and (eq name 'adapt) |
| 571 | (not (symbolp (car (cdr entry)))))) |
| 572 | (cdr entry) |
| 573 | (car (cdr entry))))))) |
| 574 | |
| 575 | (defun gnus-score-custom-set (name value) |
| 576 | (cond ((eq name 'file) |
| 577 | (setq gnus-score-custom-file value)) |
| 578 | ((assoc (symbol-name name) gnus-score-alist) |
| 579 | (if value |
| 580 | (setcdr (assoc (symbol-name name) gnus-score-alist) value) |
| 581 | (setq gnus-score-alist (delq (assoc (symbol-name name) |
| 582 | gnus-score-alist) |
| 583 | gnus-score-alist)))) |
| 584 | ((assoc (symbol-name name) gnus-header-index) |
| 585 | (if value |
| 586 | (setq gnus-score-alist |
| 587 | (cons (cons (symbol-name name) value) gnus-score-alist)))) |
| 588 | ((assoc name gnus-score-alist) |
| 589 | (cond ((null value) |
| 590 | (setq gnus-score-alist (delq (assoc name gnus-score-alist) |
| 591 | gnus-score-alist))) |
| 592 | ((and (listp value) (not (eq name 'eval))) |
| 593 | (setcdr (assoc name gnus-score-alist) value)) |
| 594 | (t |
| 595 | (setcdr (assoc name gnus-score-alist) (list value))))) |
| 596 | ((null value)) |
| 597 | ((and (listp value) (not (eq name 'eval))) |
| 598 | (setq gnus-score-alist (cons (cons name value) gnus-score-alist))) |
| 599 | (t |
| 600 | (setq gnus-score-alist |
| 601 | (cons (cons name (list value)) gnus-score-alist))))) |
| 602 | |
| 603 | (defun gnus-score-custom-sanify (entry) |
| 604 | (list (nth 0 entry) |
| 605 | (or (nth 1 entry) gnus-score-interactive-default-score) |
| 606 | (nth 2 entry) |
| 607 | (cond ((null (nth 3 entry)) |
| 608 | 's) |
| 609 | ((memq (nth 3 entry) '(before after at >= <=)) |
| 610 | (nth 3 entry)) |
| 611 | (t |
| 612 | (intern (substring (symbol-name (nth 3 entry)) 0 1)))))) |
| 613 | |
| 614 | (defvar gnus-score-cache nil) |
| 615 | |
| 616 | (defun gnus-score-custom-load () |
| 617 | (interactive) |
| 618 | (let ((file (custom-name-value 'file))) |
| 619 | (if (eq file custom-nil) |
| 620 | (error "You must specify a file name")) |
| 621 | (setq file (expand-file-name file "~/News")) |
| 622 | (gnus-score-load file) |
| 623 | (setq gnus-score-custom-file file) |
| 624 | (custom-reset-all) |
| 625 | (message "Loaded"))) |
| 626 | |
| 627 | (defun gnus-score-custom-save () |
| 628 | (interactive) |
| 629 | (custom-apply-all) |
| 630 | (gnus-score-remove-from-cache gnus-score-custom-file) |
| 631 | (let ((file gnus-score-custom-file) |
| 632 | (score gnus-score-alist) |
| 633 | emacs-lisp-mode-hook) |
| 634 | (save-excursion |
| 635 | (set-buffer (get-buffer-create "*Score*")) |
| 636 | (buffer-disable-undo (current-buffer)) |
| 637 | (erase-buffer) |
| 638 | (pp score (current-buffer)) |
| 639 | (gnus-make-directory (file-name-directory file)) |
| 640 | (write-region (point-min) (point-max) file nil 'silent) |
| 641 | (kill-buffer (current-buffer)))) |
| 642 | (message "Saved")) |
| 643 | |
| 644 | (provide 'gnus-edit) |
| 645 | |
| 646 | ;;; gnus-edit.el end here |