Merge branch 'master' of git://factorcode.org/git/factor

db4
Jason Merrill 2009-02-19 18:55:27 -05:00
commit 4e0db1332c
19 changed files with 293 additions and 233 deletions

View File

@ -19,15 +19,19 @@ ARTICLE: "compiler-usage" "Calling the optimizing compiler"
"Higher-level words can be found in " { $link "compilation-units" } "." ;
ARTICLE: "compiler" "Optimizing compiler"
"Factor is a fully compiled language implementation with two distinct compilers:"
"Factor includes two compilers which work behind the scenes. Words are always compiled, and the compilers do not have to be invoked explicitly. For the most part, compilation is fully transparent. However, there are a few things worth knowing about the compilation process."
$nl
"The two compilers differ in the level of analysis they perform:"
{ $list
{ "The " { $emphasis "non-optimizing quotation compiler" } " compiles quotations to naive machine code very quickly. The non-optimizing quotation compiler is part of the VM." }
{ "The " { $emphasis "optimizing word compiler" } " compiles whole words at a time while performing extensive data and control flow analysis. This provides greater performance for generated code, but incurs a much longer compile time. The optimizing compiler is written in Factor." }
}
"The optimizing compiler only compiles words which have a static stack effect. This means that methods defined on fundamental generic words such as " { $link nth } " should have a static stack effect; for otherwise, most of the system would be compiled with the non-optimizing compiler. See " { $link "inference" } " and " { $link "cookbook-pitfalls" } "."
{ $subsection "compiler-usage" }
"The optimizing compiler only compiles words which have a static stack effect. This means that methods defined on fundamental generic words such as " { $link nth } " should have a static stack effect. See " { $link "inference" } " and " { $link "cookbook-pitfalls" } "."
$nl
"The optimizing compiler also trades off compile time for performance of generated code, so loading certain vocabularies might take a while. Saving the image after loading vocabularies can save you a lot of time that you would spend waiting for the same code to load in every coding session; see " { $link "images" } " for information."
{ $subsection "compiler-errors" }
{ $subsection "hints" } ;
{ $subsection "hints" }
{ $subsection "compiler-usage" } ;
ABOUT: "compiler"

View File

@ -220,24 +220,6 @@ ARTICLE: "cookbook-io" "Input and output cookbook"
"io"
} ;
ARTICLE: "cookbook-compiler" "Compiler cookbook"
"Factor includes two compilers which work behind the scenes. Words are always compiled, and the compilers do not have to be invoked explicitly. For the most part, compilation is a fully transparent process. However, there are a few things worth knowing about the compilation process."
$nl
"The optimizing compiler trades off compile time for performance of generated code, so loading certain vocabularies might take a while. Saving the image after loading vocabularies can save you a lot of time that you would spend waiting for the same code to load in every coding session; see " { $link "images" } " for information."
$nl
"After loading a vocabulary, you might see messages like:"
{ $code
":errors - print 2 compiler errors."
":warnings - print 50 compiler warnings."
}
"These warnings arise from the compiler's stack effect checker. Warnings are non-fatal conditions -- not all code has a static stack effect, so you try to minimize warnings but understand that in many cases they cannot be eliminated. Errors indicate programming mistakes, such as erroneous stack effect declarations."
{ $references
"To learn more about the compiler and static stack effect inference, read these articles:"
"compiler"
"compiler-errors"
"inference"
} ;
ARTICLE: "cookbook-application" "Application cookbook"
"Vocabularies can define a main entry point:"
{ $code "IN: game-of-life"
@ -396,7 +378,6 @@ ARTICLE: "cookbook" "Factor cookbook"
{ $subsection "cookbook-io" }
{ $subsection "cookbook-application" }
{ $subsection "cookbook-scripts" }
{ $subsection "cookbook-compiler" }
{ $subsection "cookbook-philosophy" }
{ $subsection "cookbook-pitfalls" }
{ $subsection "cookbook-next" } ;

View File

@ -33,8 +33,8 @@ $nl
{ { $snippet { $emphasis "foo" } "*" } { "alternative form of " { $snippet "foo" } ", or a generic word called by " { $snippet "foo" } } { { $links at* pprint* } } }
{ { $snippet "(" { $emphasis "foo" } ")" } { "implementation detail word used by " { $snippet "foo" } } { { $link (clone) } } }
{ { $snippet "set-" { $emphasis "foo" } } { "sets " { $snippet "foo" } " to a new value" } { $links set-length } }
{ { $snippet { $emphasis "foo" } ">>" } { "gets the " { $snippet "foo" } " slot of the tuple at the top of the stack; see " { $link "accessors" } } { { $link >>name } } }
{ { $snippet ">>" { $emphasis "foo" } } { "sets the " { $snippet "foo" } " slot of the tuple at the top of the stack; see " { $link "accessors" } } { { $link name>> } } }
{ { $snippet { $emphasis "foo" } ">>" } { "gets the " { $snippet "foo" } " slot of the tuple at the top of the stack; see " { $link "accessors" } } { { $link name>> } } }
{ { $snippet ">>" { $emphasis "foo" } } { "sets the " { $snippet "foo" } " slot of the tuple at the top of the stack; see " { $link "accessors" } } { { $link >>name } } }
{ { $snippet "with-" { $emphasis "foo" } } { "performs some kind of initialization and cleanup related to " { $snippet "foo" } ", usually in a new dynamic scope" } { $links with-scope with-input-stream with-output-stream } }
{ { $snippet "$" { $emphasis "foo" } } { "help markup" } { $links $heading $emphasis } }
}

View File

@ -9,6 +9,24 @@ IN: images
SINGLETONS: BGR RGB BGRA RGBA ABGR ARGB RGBX XRGB BGRX XBGR
R16G16B16 R32G32B32 R16G16B16A16 R32G32B32A32 ;
: bytes-per-pixel ( component-order -- n )
{
{ BGR [ 3 ] }
{ RGB [ 3 ] }
{ BGRA [ 4 ] }
{ RGBA [ 4 ] }
{ ABGR [ 4 ] }
{ ARGB [ 4 ] }
{ RGBX [ 4 ] }
{ XRGB [ 4 ] }
{ BGRX [ 4 ] }
{ XBGR [ 4 ] }
{ R16G16B16 [ 6 ] }
{ R32G32B32 [ 12 ] }
{ R16G16B16A16 [ 8 ] }
{ R32G32B32A32 [ 16 ] }
} case ;
TUPLE: image dim component-order bitmap ;
: <image> ( -- image ) image new ; inline
@ -63,4 +81,4 @@ M: image normalize-scan-line-order ;
: normalize-image ( image -- image )
[ >byte-array ] change-bitmap
normalize-component-order
normalize-scan-line-order ;
normalize-scan-line-order ;

View File

@ -235,7 +235,7 @@ HELP: arg
HELP: >polar
{ $values { "z" number } { "abs" "a non-negative real number" } { "arg" "a number in the interval " { $snippet "(-pi,pi]" } } }
{ $description "Creates a complex number from an absolute value and argument (polar form)." } ;
{ $description "Converts a complex number into an absolute value and argument (polar form)." } ;
HELP: cis
{ $values { "arg" "a real number" } { "z" "a complex number on the unit circle" } }

View File

@ -87,6 +87,8 @@ HELP: inconsistent-recursive-call-error
} ;
ARTICLE: "inference-errors" "Inference warnings and errors"
"These conditions are thrown by " { $link "inference" } ", as well as the " { $link "compiler" } "."
$nl
"Main wrapper for all inference warnings and errors:"
{ $subsection inference-error }
"Inference warnings:"

View File

@ -22,7 +22,7 @@ ARTICLE: "slot-class-declaration" "Slot class declarations"
ARTICLE: "slot-class-coercion" "Coercive slot declarations"
"If the class of a slot is declared to be one of " { $link fixnum } " or " { $link float } ", then rather than testing values with the class predicate, writer words coerce values to the relevant type with " { $link >fixnum } " or " { $link >float } ". This may still result in error, but permits a wider range of values than a class predicate test. It also results in a possible loss of precision; for example, storing a large integer into a " { $link fixnum } " slot will silently overflow and discard high bits, and storing a ratio into a " { $link float } " slot may lose precision if the ratio is one which cannot be represented exactly with floating-point."
$nl
"This feature is mostly intended as an optimization for low-level code designed to avoid integer overflow, or where floating point precision is sufficient. Most code needs to work transparently with large integers, and thus hsould avoid the coercion behavior by using " { $link integer } " and " { $link real } " in place of " { $link fixnum } " and " { $link float } "." ;
"This feature is mostly intended as an optimization for low-level code designed to avoid integer overflow, or where floating point precision is sufficient. Most code needs to work transparently with large integers, and thus should avoid the coercion behavior by using " { $link integer } " and " { $link real } " in place of " { $link fixnum } " and " { $link float } "." ;
ARTICLE: "tuple-declarations" "Tuple slot declarations"
"The slot specifier syntax of the " { $link POSTPONE: TUPLE: } " parsing word understands the following slot attributes:"

View File

@ -3,9 +3,16 @@ USING: help.markup help.syntax vocabs.loader words io
quotations words.symbol ;
ARTICLE: "compiler-errors" "Compiler warnings and errors"
"The compiler saves " { $link "inference-errors" } " in a global variable:"
{ $subsection compiler-errors }
"These notifications can be viewed later:"
"After loading a vocabulary, you might see messages like:"
{ $code
":errors - print 2 compiler errors."
":warnings - print 50 compiler warnings."
}
"These warnings arise from the compiler's stack effect checker. Warnings are non-fatal conditions -- not all code has a static stack effect, so you try to minimize warnings but understand that in many cases they cannot be eliminated. Errors indicate programming mistakes, such as erroneous stack effect declarations."
$nl
"The precise warning and error conditions are documented in " { $link "inference-errors" } "."
$nl
"Words to view warnings and errors:"
{ $subsection :errors }
{ $subsection :warnings }
{ $subsection :linkage }

View File

@ -34,13 +34,20 @@ $nl
{ $subsection "vocabs.roots" }
"Vocabulary names map directly to source files. A vocabulary named " { $snippet "foo.bar" } " must be defined in a " { $snippet "bar" } " directory nested inside a " { $snippet "foo" } " directory of a vocabulary root. Any level of vocabulary nesting is permitted."
$nl
"The vocabulary directory - " { $snippet "bar" } " in our example - can contain the following files; the first is required while the rest are optional:"
"The vocabulary directory - " { $snippet "bar" } " in our example - contains a source file:"
{ $list
{ { $snippet "foo/bar/bar.factor" } " - the source file, must define words in the " { $snippet "foo.bar" } " vocabulary with an " { $snippet "IN: foo.bar" } " form" }
}
"Two other Factor source files, storing documentation and tests, respectively, are optional:"
{ $list
{ { $snippet "foo/bar/bar.factor" } " - the source file, defines words in the " { $snippet "foo.bar" } " vocabulary" }
{ { $snippet "foo/bar/bar-docs.factor" } " - documentation, see " { $link "writing-help" } }
{ { $snippet "foo/bar/bar-tests.factor" } " - unit tests, see " { $link "tools.test" } }
}
"Finally, three text files can contain meta-data:"
{ $list
{ { $snippet "foo/bar/authors.txt" } " - a series of lines, with one author name per line. These are listed under " { $link "vocab-authors" } }
{ { $snippet "foo/bar/summary.txt" } " - a one-line description" }
{ { $snippet "foo/bar/tags.txt" } " - a whitespace-separated list of tags which classify the vocabulary" }
{ { $snippet "foo/bar/tags.txt" } " - a whitespace-separated list of tags which classify the vocabulary. Consult " { $link "vocab-tags" } " for a list of existing tags you can re-use" }
}
"While " { $link POSTPONE: USE: } " and " { $link POSTPONE: USING: } " load vocabularies which have not been loaded before adding them to the search path, it is also possible to load a vocabulary without adding it to the search path:"
{ $subsection require }

View File

@ -10,7 +10,7 @@ IN: annotations
PRIVATE>
: $annotation ( element -- )
P first
first
[ "!" " your comment here" surround 1array $syntax ]
[ [ "Treats the rest of the line after the exclamation point as a code annotation that can be looked up with the " \ $link ] dip comment-usage.-word 2array " word." 3array $description ]
[ ": foo ( x y z -- w )\n !" " --w-ó()ò-w-- kilroy was here\n + * ;" surround 1array $unchecked-example ]

View File

@ -99,6 +99,8 @@ PRIVATE>
: fuel-vocab-help ( name -- ) (fuel-vocab-help) fuel-eval-set-result ;
: fuel-word-synopsis ( word usings -- ) (fuel-word-synopsis) fuel-eval-set-result ;
: fuel-vocab-summary ( name -- )
(fuel-vocab-summary) fuel-eval-set-result ;

View File

@ -90,6 +90,12 @@ PRIVATE>
: (fuel-word-help) ( name -- elem )
fuel-find-word [ [ auto-use? on (fuel-word-element) ] with-scope ] [ f ] if* ;
: (fuel-word-synopsis) ( word usings -- str/f )
[
[ vocab ] filter interactive-vocabs [ append ] change
fuel-find-word [ synopsis ] [ f ] if*
] with-scope ;
: (fuel-word-see) ( word -- elem )
[ name>> \ article swap ]
[ [ see ] with-string-writer \ $code swap 2array ] bi 3array ; inline

View File

@ -1,13 +1,19 @@
! Copyright (C) 2008 Tim Wawrzynczak
! See http://factorcode.org/license.txt for BSD license.
USING: help.markup help.syntax sequences kernel ;
USING: help.markup help.syntax sequences kernel accessors ;
IN: id3
HELP: file-id3-tags
{ $values
{ "path" "a path string" }
{ "object/f" "a tuple storing ID3 metadata or f" } }
{ $description "Return a tuple containing the ID3 information parsed out of the MP3 file, or " { $link f } " if no metadata is present." } ;
{ $description "Return a tuple containing the ID3 information parsed out of the MP3 file, or " { $link f } " if no metadata is present. Currently, the parser supports the following tags: "
$nl { $link title>> }
$nl { $link artist>> }
$nl { $link album>> }
$nl { $link year>> }
$nl { $link genre>> }
$nl { $link comment>> } } ;
ARTICLE: "id3" "ID3 tags"
"The " { $vocab-link "id3" } " vocabulary contains words for parsing " { $emphasis "ID3" } " tags, which are textual fields storing an MP3's title, artist, and other metadata." $nl

View File

@ -1,182 +1,35 @@
! Copyright (C) 2009 Tim Wawrzynczak
! See http://factorcode.org/license.txt for BSD license.
USING: tools.test id3 ;
USING: tools.test id3 id3.private ;
IN: id3.tests
[ T{ mp3v2-file
{ header T{ header f t 0 502 } }
{ frames
{
T{ frame
{ frame-id "COMM" }
{ flags B{ 0 0 } }
{ size 19 }
{ data "eng, AG# 08E1C12E" }
}
T{ frame
{ frame-id "TIT2" }
{ flags B{ 0 0 } }
{ size 15 }
{ data "Stormy Weather" }
}
T{ frame
{ frame-id "TRCK" }
{ flags B{ 0 0 } }
{ size 3 }
{ data "32" }
}
T{ frame
{ frame-id "TCON" }
{ flags B{ 0 0 } }
{ size 5 }
{ data "(96)" }
}
T{ frame
{ frame-id "TALB" }
{ flags B{ 0 0 } }
{ size 28 }
{ data "Night and Day Frank Sinatra" }
}
T{ frame
{ frame-id "PRIV" }
{ flags B{ 0 0 } }
{ size 39 }
{ data "WM/MediaClassPrimaryID<49>}`<60>#<23><>K<EFBFBD>H<EFBFBD>*(D" }
}
T{ frame
{ frame-id "PRIV" }
{ flags B{ 0 0 } }
{ size 41 }
{ data "WM/MediaClassSecondaryID" }
}
T{ frame
{ frame-id "TPE1" }
{ flags B{ 0 0 } }
{ size 14 }
{ data "Frank Sinatra" }
}
}
}
}
] [ "resource:extra/id3/tests/blah3.mp3" file-id3-tags ] unit-test
[
T{ id3-info
{ title "BLAH" }
{ artist "ARTIST" }
{ album "ALBUM" }
{ year "2009" }
{ comment "COMMENT" }
{ genre "Bluegrass" }
}
] [ "resource:extra/id3/tests/blah.mp3" file-id3-tags ] unit-test
[
T{ mp3v2-file
{ header
T{ header { version t } { flags 0 } { size 1405 } }
T{ id3-info
{ title "Anthem of the Trinity" }
{ artist "Terry Riley" }
{ album "Shri Camel" }
{ genre "Classical" }
}
{ frames
{
T{ frame
{ frame-id "TIT2" }
{ flags B{ 0 0 } }
{ size 22 }
{ data "Anthem of the Trinity" }
}
T{ frame
{ frame-id "TPE1" }
{ flags B{ 0 0 } }
{ size 12 }
{ data "Terry Riley" }
}
T{ frame
{ frame-id "TALB" }
{ flags B{ 0 0 } }
{ size 11 }
{ data "Shri Camel" }
}
T{ frame
{ frame-id "TCON" }
{ flags B{ 0 0 } }
{ size 10 }
{ data "Classical" }
}
T{ frame
{ frame-id "UFID" }
{ flags B{ 0 0 } }
{ size 23 }
{ data "http://musicbrainz.org" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 23 }
{ data "MusicBrainz Artist Id" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 22 }
{ data "musicbrainz_artistid" }
}
T{ frame
{ frame-id "TRCK" }
{ flags B{ 0 0 } }
{ size 2 }
{ data "1" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 22 }
{ data "MusicBrainz Album Id" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 21 }
{ data "musicbrainz_albumid" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 29 }
{ data "MusicBrainz Album Artist Id" }
}
T{ frame
{ frame-id "TXXX" }
{ flags B{ 0 0 } }
{ size 27 }
{ data "musicbrainz_albumartistid" }
}
T{ frame
{ frame-id "TPOS" }
{ flags B{ 0 0 } }
{ size 2 }
{ data "1" }
}
T{ frame
{ frame-id "TSOP" }
{ flags B{ 0 0 } }
{ size 1 }
}
T{ frame
{ frame-id "TMED" }
{ flags B{ 0 0 } }
{ size 4 }
{ data "DIG" }
}
}
}
}
] [ "resource:extra/id3/tests/blah2.mp3" file-id3-tags ] unit-test
[
T{ mp3v1-file
{ title
"BLAH"
}
{ artist
"ARTIST"
}
{ album
"ALBUM"
}
{ year "2009" }
{ comment
"COMMENT"
}
{ genre 89 }
}
] [ "resource:extra/id3/tests/blah.mp3" file-id3-tags ] unit-test
T{ id3-info
{ title "Stormy Weather" }
{ artist "Frank Sinatra" }
{ album "Night and Day Frank Sinatra" }
{ comment "eng, AG# 08E1C12E" }
{ genre "Big Band" }
}
] [ "resource:extra/id3/tests/blah3.mp3" file-id3-tags ] unit-test

View File

@ -1,28 +1,159 @@
! Copyright (C) 2009 Tim Wawrzynczak
! See http://factorcode.org/license.txt for BSD license.
USING: sequences io io.encodings.binary io.files io.pathnames strings kernel math io.mmap io.mmap.uchar accessors syntax combinators math.ranges unicode.categories byte-arrays prettyprint io.encodings.string io.encodings.ascii ;
USING: sequences io io.encodings.binary io.files io.pathnames strings kernel math io.mmap io.mmap.uchar accessors syntax combinators math.ranges unicode.categories byte-arrays io.encodings.string io.encodings.utf8 assocs math.parser ;
IN: id3
<PRIVATE
! genres
CONSTANT: genres
H{
{ 0 "Blues" }
{ 1 "Classic Rock" }
{ 2 "Country" }
{ 3 "Dance" }
{ 4 "Disco" }
{ 5 "Funk" }
{ 6 "Grunge" }
{ 7 "Hip-Hop" }
{ 8 "Jazz" }
{ 9 "Metal" }
{ 10 "New Age" }
{ 11 "Oldies" }
{ 12 "Other" }
{ 13 "Pop" }
{ 14 "R&B" }
{ 15 "Rap" }
{ 16 "Reggae" }
{ 17 "Rock" }
{ 18 "Techno" }
{ 19 "Industrial" }
{ 20 "Alternative" }
{ 21 "Ska" }
{ 22 "Death Metal" }
{ 23 "Pranks" }
{ 24 "Soundtrack" }
{ 25 "Euro-Techno" }
{ 26 "Ambient" }
{ 27 "Trip-Hop" }
{ 28 "Vocal" }
{ 29 "Jazz+Funk" }
{ 30 "Fusion" }
{ 31 "Trance" }
{ 32 "Classical" }
{ 33 "Instrumental" }
{ 34 "Acid" }
{ 35 "House" }
{ 36 "Game" }
{ 37 "Sound Clip" }
{ 38 "Gospel" }
{ 39 "Noise" }
{ 40 "AlternRock" }
{ 41 "Bass" }
{ 42 "Soul" }
{ 43 "Punk" }
{ 44 "Space" }
{ 45 "Meditative" }
{ 46 "Instrumental Pop" }
{ 47 "Instrumental Rock" }
{ 48 "Ethnic" }
{ 49 "Gothic" }
{ 50 "Darkwave" }
{ 51 "Techno-Industrial" }
{ 52 "Electronic" }
{ 53 "Pop-Folk" }
{ 54 "Eurodance" }
{ 55 "Dream" }
{ 56 "Southern Rock" }
{ 57 "Comedy" }
{ 58 "Cult" }
{ 59 "Gangsta" }
{ 60 "Top 40" }
{ 61 "Christian Rap" }
{ 62 "Pop/Funk" }
{ 63 "Jungle" }
{ 64 "Native American" }
{ 65 "Cabaret" }
{ 66 "New Wave" }
{ 67 "Psychedelic" }
{ 68 "Rave" }
{ 69 "Showtunes" }
{ 70 "Trailer" }
{ 71 "Lo-Fi" }
{ 72 "Tribal" }
{ 73 "Acid Punk" }
{ 74 "Acid Jazz" }
{ 75 "Polka" }
{ 76 "Retro" }
{ 77 "Musical" }
{ 78 "Rock & Roll" }
{ 79 "Hard Rock" }
{ 80 "Folk" }
{ 81 "Folk-Rock" }
{ 82 "National Folk" }
{ 83 "Swing" }
{ 84 "Fast Fusion" }
{ 85 "Bebop" }
{ 86 "Latin" }
{ 87 "Revival" }
{ 88 "Celtic" }
{ 89 "Bluegrass" }
{ 90 "Avantgarde" }
{ 91 "Gothic Rock" }
{ 92 "Progressive Rock" }
{ 93 "Psychedelic Rock" }
{ 94 "Symphonic Rock" }
{ 95 "Slow Rock" }
{ 96 "Big Band" }
{ 97 "Chorus" }
{ 98 "Easy Listening" }
{ 99 "Acoustic" }
{ 100 "Humour" }
{ 101 "Speech" }
{ 102 "Chanson" }
{ 103 "Opera" }
{ 104 "Chamber Music" }
{ 105 "Sonata" }
{ 106 "Symphony" }
{ 107 "Booty Bass" }
{ 108 "Primus" }
{ 109 "Porn Groove" }
{ 110 "Satire" }
{ 111 "Slow Jam" }
{ 112 "Club" }
{ 113 "Tango" }
{ 114 "Samba" }
{ 115 "Folklore" }
{ 116 "Ballad" }
{ 117 "Power Ballad" }
{ 118 "Rhythmic Soul" }
{ 119 "Freestyle" }
{ 120 "Duet" }
{ 121 "Punk Rock" }
{ 122 "Drum Solo" }
{ 123 "A capella" }
{ 124 "Euro-House" }
{ 125 "Dance Hall" }
} ! end genre hashtable
! tuples
TUPLE: header version flags size ;
TUPLE: frame frame-id flags size data ;
TUPLE: mp3v2-file header frames ;
TUPLE: id3v2-info header frames ;
TUPLE: mp3v1-file title artist album year comment genre ;
TUPLE: id3-info title artist album year comment genre ;
: <mp3v1-file> ( -- object ) mp3v1-file new ;
: <id3-info> ( -- object ) id3-info new ;
: <mp3v2-file> ( header frames -- object ) mp3v2-file boa ;
: <id3v2-info> ( header frames -- object ) id3v2-info boa ;
: <header> ( -- object ) header new ;
: <frame> ( -- object ) frame new ;
<PRIVATE
! utility words
: id3v2? ( mmap -- ? )
@ -59,10 +190,10 @@ TUPLE: mp3v1-file title artist album year comment genre ;
: (read-frame) ( mmap -- frame )
[ <frame> ] dip
{
[ read-frame-id ascii decode >>frame-id ]
[ read-frame-id utf8 decode >>frame-id ]
[ read-frame-flags >byte-array >>flags ]
[ read-frame-size >28bitword >>size ]
[ read-frame-data ascii decode >>data ]
[ read-frame-data utf8 decode >>data ]
} cleave ;
: read-frame ( mmap -- frame/f )
@ -98,9 +229,21 @@ TUPLE: mp3v1-file title artist album year comment genre ;
: drop-header ( mmap -- seq1 seq2 )
dup 10 tail-slice swap ;
: read-v2-tag-data ( seq -- mp3v2-file )
drop-header read-v2-header swap read-frames <mp3v2-file> ;
: parse-frames ( id3v2-info -- id3-info )
[ <id3-info> ] dip frames>>
{
[ [ frame-id>> "TIT2" = ] find nip [ data>> >>title ] when* ]
[ [ frame-id>> "TALB" = ] find nip [ data>> >>album ] when* ]
[ [ frame-id>> "TPE1" = ] find nip [ data>> >>artist ] when* ]
[ [ frame-id>> "TCON" = ] find nip [ data>> [ [ digit? ] filter string>number ] keep swap [ genres at nip ] when*
>>genre ] when* ]
[ [ frame-id>> "COMM" = ] find nip [ data>> >>comment ] when* ]
[ [ frame-id>> "TYER" = ] find nip [ data>> >>year ] when* ]
} cleave ;
: read-v2-tag-data ( seq -- id3-info )
drop-header read-v2-header swap read-frames <id3v2-info> parse-frames ;
! v1 information
: skip-to-v1-data ( seq -- seq )
@ -125,14 +268,14 @@ TUPLE: mp3v1-file title artist album year comment genre ;
[ 124 ] dip nth ;
: (read-v1-tag-data) ( seq -- mp3-file )
[ <mp3v1-file> ] dip
[ <id3-info> ] dip
{
[ read-title ascii decode filter-text-data >>title ]
[ read-artist ascii decode filter-text-data >>artist ]
[ read-album ascii decode filter-text-data >>album ]
[ read-year ascii decode filter-text-data >>year ]
[ read-comment ascii decode filter-text-data >>comment ]
[ read-genre >fixnum >>genre ]
[ read-title utf8 decode filter-text-data >>title ]
[ read-artist utf8 decode filter-text-data >>artist ]
[ read-album utf8 decode filter-text-data >>album ]
[ read-year utf8 decode filter-text-data >>year ]
[ read-comment utf8 decode filter-text-data >>comment ]
[ read-genre >fixnum genres at >>genre ]
} cleave ;
: read-v1-tag-data ( seq -- mp3-file )
@ -140,13 +283,13 @@ TUPLE: mp3v1-file title artist album year comment genre ;
PRIVATE>
! main stuff
! public interface
: file-id3-tags ( path -- object/f )
[
{
{ [ dup id3v2? ] [ read-v2-tag-data ] } ! ( ? -- mp3v2-file )
{ [ dup id3v1? ] [ read-v1-tag-data ] } ! ( ? -- mp3v1-file )
{ [ dup id3v2? ] [ read-v2-tag-data ] } ! ( ? -- id3v2 )
{ [ dup id3v1? ] [ read-v1-tag-data ] } ! ( ? -- id3-info )
[ drop f ] ! ( mmap -- f )
} cond
] with-mapped-uchar-file ;

View File

@ -111,6 +111,7 @@ beast.
| C-cC-ev | edit vocabulary (fuel-edit-vocabulary) |
| C-cC-ew | edit word (fuel-edit-word-at-point) |
| C-cC-ed | edit word's doc (C-u M-x fuel-edit-word-doc-at-point) |
| C-cC-el | load vocabs in USING: form |
|-----------------+------------------------------------------------------------|
| C-cC-er | eval region |
| C-M-r, C-cC-ee | eval region, extending it to definition boundaries |

View File

@ -32,6 +32,22 @@
:type 'boolean)
(defcustom fuel-autodoc-eval-using-form-p nil
"When enabled, automatically load vocabularies in USING: form
to display autodoc messages.
In order to show autodoc messages for words in a Factor buffer,
the used vocabularies must be loaded in the Factor image. Setting
this variable to `t' will do that automatically for you,
asynchronously. That means that you'll be able to move around
while the vocabs are being loaded, but no other FUEL
functionality will be available until loading finishes (and it
may take a while). Thus, this functionality is disabled by
default. You can force loading the vocabs in a Factor buffer
USING: form with \\[fuel-load-usings]."
:group 'fuel-autodoc
:type 'boolean)
;;; Eldoc function:
@ -41,9 +57,10 @@
(let ((word (or word (fuel-syntax-symbol-at-point)))
(fuel-log--inhibit-p t))
(when word
(let* ((cmd (if (fuel-syntax--in-using)
(let* ((usings (if fuel-autodoc-eval-using-form-p :usings t))
(cmd (if (fuel-syntax--in-using)
`(:fuel* (,word fuel-vocab-summary) :in t)
`(:fuel* (((:quote ,word) synopsis :get)) :in)))
`(:fuel* ((,word :usings fuel-word-synopsis)) t ,usings)))
(ret (fuel-eval--send/wait cmd fuel-autodoc--timeout))
(res (fuel-eval--retort-result ret)))
(when (and ret (not (fuel-eval--retort-error ret)) (stringp res))

View File

@ -77,7 +77,7 @@
(t (error "Invalid 'in' (%s)" in))))
(defsubst factor--fuel-usings (usings)
(cond ((null usings) :usings)
(cond ((or (null usings) (eq usings :usings)) :usings)
((eq usings t) nil)
((listp usings) `(:array ,@usings))
(t (error "Invalid 'usings' (%s)" usings))))

View File

@ -132,6 +132,18 @@ With prefix argument, ask for the file name."
(let ((file (car (fuel-mode--read-file arg))))
(when file (fuel-debug--uses-for-file file))))
(defun fuel-load-usings ()
"Loads all vocabularies in the current buffer's USING: from.
Useful to activate autodoc help messages in a vocabulary not yet
loaded. See documentation for `fuel-autodoc-eval-using-form-p'
for details."
(interactive)
(message "Loading all vocabularies in USING: form ...")
(let ((err (fuel-eval--retort-error
(fuel-eval--send/wait '(:fuel* (t) t :usings) 120000))))
(message (if err "Warning: some vocabularies failed to load"
"All vocabularies loaded"))))
;;; Minor mode definition:
@ -191,7 +203,8 @@ interacting with a factor listener is at your disposal.
(fuel-mode--key ?e ?d 'fuel-edit-word-doc-at-point)
(fuel-mode--key ?e ?e 'fuel-eval-extended-region)
(fuel-mode--key ?e ?l 'fuel-run-file)
(fuel-mode--key ?e ?k 'fuel-run-file)
(fuel-mode--key ?e ?l 'fuel-load-usings)
(fuel-mode--key ?e ?r 'fuel-eval-region)
(fuel-mode--key ?e ?u 'fuel-update-usings)
(fuel-mode--key ?e ?v 'fuel-edit-vocabulary)